name: CI Checks
on:
workflow_call:
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: -Dwarnings
jobs:
fmt:
name: Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
with:
components: rustfmt
- run: cargo fmt --check
clippy:
name: Clippy
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@v2
with:
tool: clippy-sarif,sarif-fmt
- name: Run clippy with SARIF output
run: |
set -eo pipefail
cargo clippy --all-targets --message-format=json -- \
--force-warn=clippy::cognitive_complexity \
--force-warn=clippy::too_many_lines \
| clippy-sarif \
| tee clippy.sarif \
| sarif-fmt
- name: Render clippy summary
if: always()
env:
REPO: ${{ github.repository }}
SHA: ${{ github.sha }}
run: |
if [[ ! -f clippy.sarif ]]; then
echo "_clippy.sarif was not generated._" >> "$GITHUB_STEP_SUMMARY"
exit 0
fi
python3 - >> "$GITHUB_STEP_SUMMARY" <<'PY'
import json, os, re
from collections import defaultdict
repo = os.environ.get("REPO", "")
sha = os.environ.get("SHA", "")
with open("clippy.sarif") as f:
sarif = json.load(f)
# rule -> {(file, line): value} — dedupes lib + lib-test duplicates
seen = defaultdict(dict)
for run in sarif.get("runs", []):
for r in run.get("results", []):
rule = r.get("ruleId", "") or "(unknown)"
msg = (r.get("message") or {}).get("text", "")
m = re.search(r"\((\d+)/\d+\)", msg)
val = int(m.group(1)) if m else 0
for loc in r.get("locations", []):
phys = loc.get("physicalLocation", {})
art = phys.get("artifactLocation", {}).get("uri", "?")
line = phys.get("region", {}).get("startLine", 0)
seen[rule][(art, line)] = val
total = sum(len(v) for v in seen.values())
print(f"## Clippy complexity findings: **{total}**\n")
if not seen:
print("_All clean — no complexity warnings._")
else:
for rule in sorted(seen.keys()):
short = rule.split("::")[-1]
items = sorted(seen[rule].items(), key=lambda kv: -kv[1])
print(f"### `{short}` — {len(items)} findings\n")
print("| File | Line | Value |")
print("|---|---:|---:|")
for (path, line), val in items:
url = f"https://github.com/{repo}/blob/{sha}/{path}#L{line}" if repo and sha else ""
label = f"[`{path}`]({url})" if url else f"`{path}`"
print(f"| {label} | {line} | {val} |")
print()
PY
- name: Upload SARIF to GitHub Code Scanning
if: success() || failure()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: clippy.sarif
wait-for-processing: true
category: clippy
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools-preview
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@v2
with:
tool: cargo-llvm-cov
- name: Run tests with coverage
run: cargo llvm-cov --all-targets --lcov --output-path lcov.info
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
files: lcov.info
fail_ci_if_error: false
audit:
name: Security Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: rustsec/audit-check@v2.0.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
deny:
name: Cargo Deny
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: EmbarkStudios/cargo-deny-action@v2
msrv:
name: MSRV (1.86.0)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.86.0
- uses: Swatinem/rust-cache@v2
- run: cargo check
package:
name: Package (cargo publish --dry-run)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo publish --dry-run