ripbi-core 0.2.1

Static analysis engine for Power BI semantic models: TMDL and PBIR ingestion, DAX reference extraction, dependency graph, and reachability
Documentation

ripbi

CI crates.io

Static analysis, linting, and tree-shaking for Power BI semantic models and DAX.

Docs: bgarcevic.github.io/ripbi.

I created ripbi because I liked Measure Killer, but I was looking for an agent-friendly, free, fast tool to scan semantic models and the connected reports to identify potentially unused semantic model objects. I tested it on a shared semantic model with 14 connected reports, and it's 99% faster than Measure Killer, reducing processing time from almost 4 minutes to a couple of seconds.

It works without opening the reports or semantic models, so it can run as part of a CI pipeline. It's also cross-platform, with no dependency on Power BI Desktop or similar.

It currently works only on local PBIP projects — a TMDL semantic model plus PBIR reports; .pbix and .pbit files are not supported yet. I plan to implement guided automated cleanup, a UI, and tenant scanning.

Install

macOS and Linux:

curl -fsSL https://raw.githubusercontent.com/bgarcevic/ripbi/main/install.sh | sh

Windows (PowerShell):

irm https://raw.githubusercontent.com/bgarcevic/ripbi/main/install.ps1 | iex

Both scripts verify the download against the release's sha256 checksums and install the binary into ~/.local/bin as both ripbi and its short alias rib — the two names are the same tool, so rib scan works anywhere ripbi scan does. Or cargo install ripbi.

Pin a version:

curl -fsSL https://raw.githubusercontent.com/bgarcevic/ripbi/main/install.sh | RIPBI_VERSION=v0.2.1 sh
$env:RIPBI_VERSION = 'v0.2.1'; irm https://raw.githubusercontent.com/bgarcevic/ripbi/main/install.ps1 | iex

Both scripts are plain shell and PowerShell. Download them first if you would rather read before running:

curl -fsSL https://raw.githubusercontent.com/bgarcevic/ripbi/main/install.sh -o install.sh
sh install.sh
irm https://raw.githubusercontent.com/bgarcevic/ripbi/main/install.ps1 -OutFile install.ps1
powershell -ExecutionPolicy Bypass -File .\install.ps1  # the flag is only needed if your policy blocks script files

From a clone of this repository:

cargo install --path crates/ripbi-cli

Updating

Installed with one of the scripts above? ripbi update downloads the latest release, verifies its sha256 checksum, and replaces ripbi and rib in place:

ripbi update           # update in place; exits 0 when done
ripbi update --check   # report only: exits 1 when a newer release exists

Exit codes: 0 updated or up to date, 1 update available (only from --check), 2 error (network, checksum, unsupported platform).

Every command checks for a new release at most once a day and prints a dim one-line notice when one is available. That check is a plain GET of the public release metadata — no data is sent — and RIPBI_NO_UPDATE_CHECK=1 disables it. It is also skipped automatically when stderr is not a terminal (pipes, CI logs), when CI is set, or under -q.

Cargo-installed copies are never self-replaced: ripbi update prints the cargo install ripbi --force command instead. A source build found under a target/ directory prints the install-script and cargo install --path alternatives.

On Windows a running executable cannot be deleted, so a completed update may leave ripbi.exe.old (or rib.exe.old) beside the new binary. It is safe to delete, and the next update removes it.

Quickstart

Clone the repository to get the sample projects, then scan one:

git clone https://github.com/bgarcevic/ripbi.git
cd ripbi
ripbi scan "samples/AdventureWorks Sales.pbip"

Output from the committed AdventureWorks sample (trimmed):

130 objects, 74 reachable from 51 roots, 56 unused

Measures (11)
  'Sales'[Average Sales per Order]
    ← nothing references it
Columns (28)
  'Customer'[City]
    ← only used by hierarchy 'Customer'[Geography] — hierarchy level (also unused)
  …

The summary line counts the model's objects, how many the reports reach, and how many are unused. Each finding says why it is dead: nothing references it, or its only consumer is itself unused.

ripbi scan discovers the project itself: pass a .pbip file, a project folder, a .SemanticModel, or a .Report, or nothing to scan the current directory.

To scan one named model against every report bound to it, pass --model; each --report folder is searched recursively for reports bound to that model:

ripbi scan --model "samples/AdventureWorks Sales.SemanticModel" --report samples/

Exit codes:

Code Meaning
0 Nothing unused
1 Unused objects found
2 Error (bad path, ingestion failure, …)
ripbi scan -q   # no output; exit code only

Output

The full output contract (human, --summary, --plain, --json, and ripbi.toml configuration) is documented in the user guide's scan chapter.

Contributing

Dev setup, workflow, and where things live are documented in CONTRIBUTING.md. The short version — CI is the definition of done, and this is what CI runs:

cargo fmt --all --check
cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps --all-features --locked
cargo test --workspace

License

Dual-licensed under MIT or Apache-2.0. The samples/ are Microsoft's own sample projects (MIT) and are not covered by ripbi's license.