Files
cleveragents-core/.forgejo/workflows/nightly-quality.yml
freemo 99aa459bad chore(ci): consolidate uv cache key across all workflow jobs
Replace per-job cache key prefixes (uv-lint-, uv-typecheck-, uv-security-,
uv-quality-, uv-tests-, uv-coverage-) with a single shared key
uv-${{ hashFiles('pyproject.toml') }} across all jobs in ci.yml.

Also add a missing uv cache step to the build job and add uv caching
to nightly-quality.yml, which previously had no cache at all.

All jobs now share the same cache entry when pyproject.toml is unchanged,
eliminating redundant package downloads and reducing CI wall-clock time.

ISSUES CLOSED: #1535
2026-04-02 23:20:11 +00:00

133 lines
4.2 KiB
YAML

name: Nightly Quality
on:
schedule:
# Run at midnight UTC every day
- cron: "0 0 * * *"
workflow_dispatch:
# Allow manual trigger for testing
env:
UV_VERSION: "0.8.0"
PYTHON_VERSION: "3.13"
RUFF_VERSION: ">=0.15,<0.16"
jobs:
full-quality-suite:
runs-on: docker
container:
image: python:3.13-slim
steps:
- name: Install system dependencies (git for merge tests)
run: |
apt-get update && apt-get install -y -qq git && rm -rf /var/lib/apt/lists/*
- uses: actions/checkout@v4
- name: Install uv
run: |
pip install -q uv==${{ env.UV_VERSION }}
- name: Cache uv packages
uses: actions/cache@v3
with:
path: ~/.cache/uv
key: uv-${{ hashFiles('pyproject.toml') }}
restore-keys: |
uv-
- name: Install all dependencies
run: |
uv pip install --system -e ".[dev,tests]"
- name: Ensure pinned ruff version
run: |
uv pip install --system "ruff${{ env.RUFF_VERSION }}"
- name: Install behave-parallel
run: |
pip install -q behave-parallel
- name: Run full lint suite
run: |
ruff format --check .
ruff check .
- name: Run pyright type checking
run: |
pyright
- name: Run bandit security scan (all severities)
run: |
mkdir -p build/reports
bandit -c pyproject.toml -r src/cleveragents --format json --output build/reports/bandit-full.json || true
bandit -c pyproject.toml -r src/cleveragents --severity-level high
- name: Run vulture dead code detection
run: |
vulture src/cleveragents vulture_whitelist.py --min-confidence 80 --exclude src/cleveragents/discovery
- name: Run radon complexity analysis
run: |
mkdir -p build/reports
radon cc src/cleveragents --show-complexity --total-average --json > build/reports/complexity.json
radon mi src/cleveragents --json > build/reports/maintainability.json
echo "=== Complexity Summary ==="
radon cc src/cleveragents --min C --show-complexity --total-average
echo "=== Maintainability Index ==="
radon mi src/cleveragents --min B
- name: Run full Behave test suite with coverage
run: |
coverage run --source=src -m behave -q --no-capture || true
coverage xml -o build/reports/coverage.xml
coverage json -o build/reports/coverage.json
coverage report --fail-under=85
- name: Run quality gates script
run: |
python scripts/check-quality-gates.py --coverage-min 85 --complexity-max F
- name: Generate quality trend data
run: |
python -c "
import json, datetime
from pathlib import Path
report = {
'timestamp': datetime.datetime.now(datetime.timezone.utc).isoformat(),
'gates': {}
}
# Coverage
cov_path = Path('build/reports/coverage.json')
if cov_path.exists():
cov_data = json.loads(cov_path.read_text())
summary = cov_data.get('summary') or cov_data.get('totals') or {}
report['gates']['coverage'] = summary.get('percent_covered', 0)
# Complexity
cx_path = Path('build/reports/complexity.json')
if cx_path.exists():
cx_data = json.loads(cx_path.read_text())
total_blocks = sum(len(b) for b in cx_data.values())
report['gates']['total_analyzed_blocks'] = total_blocks
# Security
sec_path = Path('build/reports/bandit-full.json')
if sec_path.exists():
sec_data = json.loads(sec_path.read_text())
report['gates']['security_issues'] = len(sec_data.get('results', []))
Path('build/reports/quality-trend.json').write_text(json.dumps(report, indent=2))
print(json.dumps(report, indent=2))
"
- name: Upload quality reports
if: always()
uses: actions/upload-artifact@v4
with:
name: nightly-quality-reports
path: build/reports/
retention-days: 90