Code analysis and quality metrics tracking system for CI/CD pipelines.
umpyre provides automated code metrics collection and tracking for Python projects, designed to integrate seamlessly with GitHub Actions CI/CD pipelines. Track code quality trends over time with minimal overhead.
Key Features:
- π― Pluggable collectors: Workflow status, complexity (wily), coverage, code statistics
- π Git-based storage: Metrics stored in separate branch, no external dependencies
- βοΈ Config-driven: Customize via YAML configuration
- π Fast & lightweight: Limited history tracking for speed
- π GitHub Action: Drop-in integration for existing workflows
pip install umpyreCreate .github/umpyre-config.yml:
schema_version: "1.0"
collectors:
workflow_status:
enabled: true
lookback_runs: 10
coverage:
enabled: true
source: pytest-cov
umpyre_stats:
enabled: true
exclude_dirs: [tests, examples, scrap]
storage:
branch: code-metrics
formats: [json, csv]In your .github/workflows/ci.yml (after successful PyPI publish):
- name: Track Code Metrics
if: success() # Only track metrics after successful publish
uses: i2mint/umpyre/actions/track-metrics@master
continue-on-error: true # Never fails CI - see FAILURE_PROTECTION.md
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
config-path: .github/umpyre-config.yml # Optional: defaults to this pathImportant: Metrics collection has triple-layer failure protection and will never break your CI pipeline. See FAILURE_PROTECTION.md for details.
Metrics are stored in the code-metrics branch:
metrics.json- Latest snapshotmetrics.csv- Flat format for analysishistory/- Flat historical records (filename format:YYYY_MM_DD_HH_MM_SS__commit__version.json)
See STORAGE_STRUCTURE.md for full details on storage design and querying.
# Collect and store metrics
python -m umpyre.cli collect
# Collect with custom config
python -m umpyre.cli collect --config my-config.yml
# Dry run (don't store)
python -m umpyre.cli collect --no-store
# Validate against thresholds (coming soon)
python -m umpyre.cli validateMetrics are stored in a flat structure with parseable filenames: YYYY_MM_DD_HH_MM_SS__shahash__version.json
# Switch to metrics branch
git checkout code-metrics
# Get all metrics from November 14
ls history/2025_11_14_*
# Find metrics for specific commit
ls history/*__700e012__*
# Find all v0.1.0 metrics
ls history/*__0.1.0.json
# Get latest 10 metrics
ls -t history/ | head -10
# Exclude metrics without version
ls history/ | grep -v "__none.json"from pathlib import Path
from umpyre.storage import (
parse_metric_filename,
find_metrics_by_commit,
find_metrics_by_version,
get_latest_metric_for_version,
get_all_versions,
)
history_dir = Path("history")
# Parse filename
info = parse_metric_filename("2025_11_14_22_45_00__700e012__0.1.0.json")
print(info['commit_sha']) # '700e012'
print(info['pypi_version']) # '0.1.0'
print(info['timestamp']) # datetime object
# Find by commit
metrics = find_metrics_by_commit(history_dir, "700e012")
# Find all metrics for a version
all_v0_1_0 = find_metrics_by_version(history_dir, "0.1.0")
# Get latest metric for a version
latest = get_latest_metric_for_version(history_dir, "0.1.0")
# List all versions
versions = get_all_versions(history_dir)
print(versions) # ['0.1.0', '0.1.1', '0.2.0']See STORAGE_STRUCTURE.md for detailed storage design documentation.
Tracks GitHub CI/CD health via API:
- Last run status (success/failure)
- Recent failure count
- Last successful run timestamp
Extracts test coverage from pytest-cov or coverage.py:
- Line coverage %
- Branch coverage %
- Supports JSON and XML formats
Complexity metrics using wily (requires installation):
- Cyclomatic complexity
- Maintainability index
- Limited to recent commits for speed
Code statistics using built-in analyzer:
- Function/class counts
- Line metrics (total, empty, comments, docs)
- Code ratios and averages
See .github/umpyre-config.yml for full options:
schema_version: "1.0" # Required
collectors:
workflow_status:
enabled: true
lookback_runs: 10 # Number of recent runs to analyze
wily:
enabled: true
max_revisions: 5 # Limit for performance
operators: [cyclomatic, maintainability]
coverage:
enabled: true
source: pytest-cov # or 'coverage'
umpyre_stats:
enabled: true
exclude_dirs: [tests, examples, scrap]
storage:
branch: code-metrics # Branch name for metrics
formats: [json, csv] # Output formats
retention:
strategy: all # or: last_n_days, last_n_commits
visualization: # Coming in Phase 2
generate_plots: true
generate_readme: true
plot_metrics: [maintainability, coverage, loc]
thresholds: # Coming in Phase 3
enabled: false
aggregation: # Coming in Phase 2
enabled: falseumpyre/
βββ collectors/ # Metric collectors (pluggable)
β βββ base.py # Abstract Collector with Mapping interface
β βββ workflow_status.py
β βββ wily_collector.py
β βββ coverage_collector.py
β βββ umpyre_collector.py
βββ storage/ # Persistence layer
β βββ git_branch.py # Git-based storage
β βββ formats.py # JSON/CSV serialization
βββ config.py # YAML config loading
βββ schema.py # Versioned metric schema
βββ cli.py # Command-line interface
{
"schema_version": "1.0",
"timestamp": "2025-01-15T10:30:00Z",
"commit_sha": "abc123...",
"commit_message": "Fix bug in parser",
"python_version": "3.10",
"workflow_status": {
"last_run_status": "success",
"recent_failure_count": 0
},
"metrics": {
"complexity": {
"cyclomatic_avg": 3.2,
"maintainability_index": 75.3
},
"coverage": {
"line_coverage": 87.5,
"branch_coverage": 82.1
},
"code_stats": {
"num_functions": 342,
"num_classes": 28
}
},
"collection_duration_seconds": 12.3
}Phase 1 (β Complete): Core tracking system
- Config-driven collectors
- Git branch storage
- CLI and GitHub Action
Phase 2 (Planned): Visualization & Aggregation
- Plot generation (matplotlib/plotly)
- Auto-generated README with charts
- Cross-repository aggregation
- Organization-wide dashboards
Phase 3 (Planned): Advanced Features
- Security metrics (bandit)
- Docstring coverage (interrogate)
- Threshold validation with custom validators
- Data pruning and compression
- Schema migration utilities
Contributions welcome! See misc/CHANGELOG.md for recent changes.
Get stats about packages (existing functionality preserved):
from umpyre import modules_info_df, stats_of
import collections
# Analyze a single package
modules_info_df(collections)
# Compare multiple packages
stats_of(['urllib', 'json', 'collections'])See original README examples above for detailed usage.
Apache-2.0