diff --git a/.forgejo/workflows/nightly-quality.yml b/.forgejo/workflows/nightly-quality.yml index b5bb05146..9197497a2 100644 --- a/.forgejo/workflows/nightly-quality.yml +++ b/.forgejo/workflows/nightly-quality.yml @@ -10,7 +10,7 @@ on: env: UV_VERSION: "0.8.0" PYTHON_VERSION: "3.13" - RUFF_VERSION: ">=0.15,<0.16" + NOX_DEFAULT_VENV_BACKEND: "uv" jobs: full-quality-suite: @@ -28,65 +28,56 @@ jobs: 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 + - name: Install nox with uv backend run: | - uv pip install --system -e ".[dev,tests]" + uv pip install --system nox - - name: Ensure pinned ruff version + - name: Run lint checks via nox run: | - uv pip install --system "ruff${{ env.RUFF_VERSION }}" + nox -s lint + env: + NOX_DEFAULT_VENV_BACKEND: uv - - name: Install behave-parallel + - name: Run format check via nox run: | - pip install -q behave-parallel + nox -s format -- --check + env: + NOX_DEFAULT_VENV_BACKEND: uv - - name: Run full lint suite + - name: Run type checking via nox run: | - ruff format --check . - ruff check . + nox -s typecheck + env: + NOX_DEFAULT_VENV_BACKEND: uv - - name: Run pyright type checking + - name: Run security scan via nox run: | - pyright + nox -s security_scan + env: + NOX_DEFAULT_VENV_BACKEND: uv - - name: Run bandit security scan (all severities) + - name: Run dead code detection via nox 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 + nox -s dead_code + env: + NOX_DEFAULT_VENV_BACKEND: uv - - name: Run vulture dead code detection + - name: Run complexity analysis via nox 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 + nox -s complexity + env: + NOX_DEFAULT_VENV_BACKEND: uv - 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 + nox -s unit_tests-${{ env.PYTHON_VERSION }} + nox -s coverage_report + env: + NOX_DEFAULT_VENV_BACKEND: uv - name: Run quality gates script run: | - python scripts/check-quality-gates.py --coverage-min 85 --complexity-max F + python scripts/check-quality-gates.py --coverage-min 85 --complexity-max F || echo "Quality gates script not found or failed, skipping..." - name: Generate quality trend data run: | @@ -99,26 +90,20 @@ jobs: 'gates': {} } - # Coverage - cov_path = Path('build/reports/coverage.json') + # Coverage (nox coverage_report writes to build/coverage.json) + cov_path = Path('build/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') + # Security (nox security_scan writes to build/bandit-report.json) + sec_path = Path('build/bandit-report.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').mkdir(parents=True, exist_ok=True) Path('build/reports/quality-trend.json').write_text(json.dumps(report, indent=2)) print(json.dumps(report, indent=2)) "