CI / Diff-Based Analysis
View SourceMetaCredo supports diff-based analysis for CI/CD pipelines. Only files changed in a pull request are checked, giving fast, focused feedback.
Quick Start
# Analyze only changed files, fail on issues
mix metacredo --diff --strict
# With GitHub Actions inline PR annotations
mix metacredo --diff --format github --strict
Diff Mode
When --diff is given, MetaCredo resolves the list of files changed
between two git refs and runs checks only on those files. This is much
faster than analyzing the entire project and avoids reporting pre-existing
issues that are unrelated to the current PR.
How it works
MetaCredo.Git.changed_files/2runsgit diff --name-only --diff-filter=ACMR <base>...<head>- The result is filtered to supported extensions (
.ex,.exs,.erl,.hrl,.py,.rb,.hs) - The file list is passed as
:files_includedto the execution pipeline - Checks run only on those files
Options
--diff Enable diff-based mode
--base REF Base git ref (default: origin/main)
--head REF Head git ref (default: HEAD)
--format FORMAT Output format: text (default), json, github
--strict Only report normal+ priority issues
--only CATEGORIES Comma-separated categories (security,warning,...)
--ignore CATEGORIES Comma-separated categories to skipExamples
# Default: diff against origin/main
mix metacredo --diff
# Custom base branch
mix metacredo --diff --base origin/develop
# Strict mode + GitHub annotations
mix metacredo --diff --strict --format github
# Only security checks on changed files
mix metacredo --diff --only security --format github
# JSON output for downstream tooling
mix metacredo --diff --format json
GitHub Actions Format
Use --format github to produce GitHub Actions workflow commands:
::error file=lib/repo.ex,line=42::HardcodedValue: Hardcoded URL found
::warning file=lib/worker.ex,line=15::MissingErrorHandling: Missing error handling
::notice file=lib/utils.ex,line=3::ModuleDoc: Module missing documentation
metacredo: 3 issue(s) foundGitHub renders these as inline annotations on the PR diff:
::errorfor severity:error(red)::warningfor severity:warning(yellow)::noticefor severity:infoand:refactoring_opportunity(grey)
GitHub Actions Integration
Standalone job
metacredo:
name: MetaCredo Analysis
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Required for git diff
- uses: erlef/setup-beam@v1
with:
elixir-version: '1.19'
otp-version: '28'
- name: Restore deps cache
uses: actions/cache@v4
with:
path: deps
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
- run: mix deps.get
- run: mix metacredo --diff --base origin/${{ github.base_ref }} --format github --strictNotes:
fetch-depth: 0is required sogit diffcan see the base branch.origin/${{ github.base_ref }}is the PR target (e.g.origin/main).
Combined with Ragex
If your project uses Ragex, a single command runs both tools:
- run: mix ragex.ci --base origin/${{ github.base_ref }} --format githubSee the Ragex CI guide for details.
Other CI Systems
GitLab CI
metacredo:
stage: test
only:
- merge_requests
script:
- mix deps.get
- mix metacredo --diff --base origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME --strictGeneric
#!/bin/bash
BASE="${CI_BASE_REF:-origin/main}"
mix metacredo --diff --base "$BASE" --strict
API: MetaCredo.Git
The MetaCredo.Git module provides a lightweight git integration with no
external dependencies beyond the git binary:
# Find the repo root
root = MetaCredo.Git.repo_root("/path/inside/repo")
# => "/path/to/repo"
# Get changed files
{:ok, files} = MetaCredo.Git.changed_files(root,
base: "origin/main",
head: "HEAD",
extensions: [".ex", ".exs"]
)
# => {:ok, ["lib/foo.ex", "lib/bar.ex"]}
# Bang version (raises on error)
files = MetaCredo.Git.changed_files!(root)Options for changed_files/2
:base-- base git ref (default:"origin/main"):head-- head git ref (default:"HEAD"):filter-- git diff status filter (default:"ACMR", excludes deleted):extensions-- list of file extensions to keep (default: all)
Troubleshooting
"fatal: bad revision 'origin/main...HEAD'"
Ensure the CI checkout fetches the full history (fetch-depth: 0) or
fetch the base branch explicitly:
git fetch origin main
mix metacredo --diff
"No changed files found in diff"
Expected when only non-code files changed. The task exits with code 0.
"--diff requires a git repository, but none was found"
The working directory is not inside a git repo. In CI, the checkout step should handle this automatically.
Version: MetaCredo 0.2.0 Last Updated: May 2026