Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BloatBot

Marketplace CI Release License

On every pull request, BloatBot tells you why your compiled binary changed size — attributing the byte delta to specific dependencies and to your own code — instead of just telling you that it changed.

Existing size tools (size-limit, bundlewatch, cargo-bloat in isolation) report a number: "binary +47 KB." They stop there. You're left asking the only question that matters — what did this to me? — and have to go dig.

BloatBot answers it directly:

Your release binary grew +47 KB (+3.1%). 41 KB of that is serde_json, newly pulled in by your change to src/config.rs. The remaining 6 KB is your own code. No existing dependency shrank.

The diffing primitives already exist (cargo bloat, cargo tree, Cargo.lock). BloatBot's value is the PR workflow, the dependency attribution, and a comment a human actually reads.


Example comment

📦 Binary size: myapp grew +47.0 KiB (+3.1%)

1.48 MiB → 1.53 MiB, gzip 512 KiB → 528 KiB

.text attribution: +41.0 KiB from dependencies, +6.0 KiB from your code.

Crate Base Head Δ Δ%
🆕 serde_json 0 B 41.0 KiB +41.0 KiB new
🔺 myapp (you) 54.0 KiB 60.0 KiB +6.0 KiB +11.1%

New dependencies introduced by this PR:

  • serde_json (+41.0 KiB) — pulled in via myapp → config-loader → serde_json (added in Cargo.lock)

Base a1b2c3d · head e4f5g6h · toolchain 1.97.1.


Quick start (GitHub Action)

# .github/workflows/size.yml
name: Binary size
on: pull_request
permissions:
  contents: read
  pull-requests: write      # to post the sticky comment
jobs:
  size:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0     # BloatBot builds the base ref, so it needs history
      - uses: Asuddle/BloatBot@v1
        with:
          bin: myapp         # which binary to measure (required)
          # threshold-percent: "5"   # optional: fail the check if it grows >5%

That's it. On each PR, BloatBot builds the base and head refs, diffs them per-crate, and posts a single sticky comment that it updates in place on every push.

Action inputs

Input Default Description
bin (required) Binary target to analyze. Workspaces have several, so this is required.
manifest-path Cargo.toml Path to the Cargo.toml to analyze.
cargo-args "" Extra flags forwarded to both builds, e.g. --features foo.
noise-floor 512 Ignore per-crate changes below this many bytes (compiler jitter).
threshold-percent "" Fail the check if the binary grows by more than this percent. Empty = never fail.
comment true Post/patch the sticky PR comment.
github-token ${{ github.token }} Token used to comment.

Try it locally first

BloatBot's core is a plain CLI — no CI required. If it isn't useful in your terminal, it won't be useful as a bot, so prove it there first:

cargo install cargo-bloat            # the underlying analyzer
cargo install --path .               # build bloatbot

# Two git refs in, a ranked crate-level diff out:
bloatbot diff main HEAD --bin myapp

Other subcommands:

# Produce one side's per-crate breakdown as JSON (the intermediate data model):
bloatbot analyze --bin myapp --ref HEAD -o head.json

# Diff two breakdown JSONs — pure, no build, no git (great for tests/CI seams):
bloatbot compare base.json head.json
bloatbot compare base.json head.json --json    # machine-readable

How it works

  1. Analyze each ref: build the target in release mode, run cargo bloat --release --crates --message-format json, and record a per-crate .text size map plus file size, gzip size, and toolchain into a Breakdown.
  2. Compare (pure): delta = head[crate] − base[crate] for every crate, ranked by absolute delta. New crates (in head, not base) are the interesting case. Workspace-local crates are split out as "your code." A noise floor folds sub-threshold jitter away so we don't cry wolf over 12 bytes. (src/compare.rs — no cargo, git, or GitHub; unit-tested from JSON.)
  3. Attribute the cause — the differentiator. For each newly-appeared crate, diff Cargo.lock (newly-locked → "added by this PR") and run cargo tree --invert <crate> to reconstruct the chain that dragged it in: myapp → config-loader → serde_json. (src/attribute.rs)
  4. Render a Markdown comment: headline first, one focused table, the "why" callout, everything else collapsed behind a <details>. (src/render.rs)
  5. Post a sticky comment carrying a hidden <!-- bloatbot --> marker, PATCHing the existing one on re-runs instead of spamming. (scripts/post-comment.sh)

The base/head measurement strategy

BloatBot rebuilds the base ref in the same job and measures both sides with the same toolchain, so the diff is real signal rather than compiler noise. That's two builds per PR; Swatinem/rust-cache means only changed code recompiles. (A stored-baseline optimization — one build per PR, diffing against a map recorded on merge — is a documented future option; correctness first.)


Honest scope

MVP: Rust binaries, per-crate granularity. That's a deliberate, narrow target where cargo bloat --crates and cargo tree hand you clean data almost for free.

Explicitly not now (written down so scope doesn't creep): JS/wasm/Go, function-level breakdown, multi-artifact repos, a web dashboard, historical trends.

This is a strong OSS tool and a genuinely useful portfolio piece — not a business. The audience ("Rust teams that care about binary size") is real but small. Built because the attribution problem is satisfying to solve.

Known footguns handled

  • Fork PRs get a read-only token and can't comment. BloatBot always writes the report to the job summary too, so a fork PR still shows its size impact.
  • Toolchain drift would show up as fake deltas; the toolchain is recorded and a mismatch is flagged in the comment.
  • Which binarycargo bloat measures exactly one artifact, so bin is required.

Development

cargo test --all      # 10 unit + 4 CLI integration tests, no toolchain magic needed
cargo clippy --all-targets -- -D warnings

BloatBot runs on itself in CI — see .github/workflows/size.yml.

License

Licensed under either of MIT or Apache-2.0 at your option.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages