Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 206 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
name: CI

on:
push:
branches: [main, feat/**]
pull_request:
branches: [main]
workflow_dispatch:

env:
PYTHON_VERSION: "3.12"

jobs:
# ============================================================
# Job 1: 单元测试 (Unit Tests)
# ============================================================
test:
name: Unit Tests
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: "pip"
cache-dependency-path: requirements.txt

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install aiosqlite # async SQLite driver for tests

- name: Run pytest
run: |
python -m pytest tests/ \
-v \
--tb=short \
--strict-markers \
-x

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: test-results/
retention-days: 7

# ============================================================
# Job 2: 类型检查 (Type Checking)
# ============================================================
type-check:
name: Type Check
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: "pip"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install mypy types-python-dateutil types-PyYAML

- name: Run mypy
run: |
python -m mypy . --ignore-missing-imports --warn-unused-ignores --disallow-untyped-defs || true
continue-on-error: true

# ============================================================
# Job 3: 安全扫描 (Security Scan)
# ============================================================
security:
name: Security Scan
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: "pip"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install bandit safety

- name: Run Bandit security scan
run: |
bandit -r . -f json -o bandit-report.json || true
continue-on-error: true

- name: Run Safety dependency check
run: |
safety check --json --output safety-report.json || true
continue-on-error: true

- name: Upload security reports
uses: actions/upload-artifact@v4
with:
name: security-reports
path: |
bandit-report.json
safety-report.json
retention-days: 7
if-no-files-found: ignore

# ============================================================
# Job 4: 代码质量检查 (Code Quality)
# ============================================================
lint:
name: Code Quality
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: "pip"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 ruff

- name: Run Ruff lint
run: ruff check .

- name: Run Flake8
run: |
flake8 . \
--max-line-length=120 \
--extend-ignore=E203,W503 \
--exclude=.venv,__pycache__,.git \
|| true
continue-on-error: true

# ============================================================
# Job 5: 覆盖率报告 (Coverage Report)
# ============================================================
coverage:
name: Coverage Report
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: "pip"
cache-dependency-path: requirements.txt

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install aiosqlite coverage pytest-cov

- name: Generate coverage report
run: |
python -m coverage run -m pytest tests/ -v --tb=short -x
python -m coverage report --fail-under=60 --omit=".venv/*,tests/*"
python -m coverage html -d coverage-html

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
if: always()
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
fail_ci_if_error: false

- name: Upload coverage HTML report
uses: actions/upload-artifact@v4
if: always()
with:
name: coverage-html
path: coverage-html/
retention-days: 7
143 changes: 143 additions & 0 deletions .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
name: Code Quality

on:
push:
branches: [main, feat/**]
pull_request:
schedule:
# 每周一早上 9:00 UTC 运行代码质量检查
- cron: "0 9 * * 1"

env:
PYTHON_VERSION: "3.12"

jobs:
# ============================================================
# Job 1: Pre-commit 检查
# ============================================================
pre-commit:
name: Pre-commit Hooks
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: "pip"

- name: Install pre-commit
run: pip install pre-commit

- name: Install pre-commit hooks
run: pre-commit install --install-hooks

- name: Run pre-commit on all files
run: pre-commit run --all-files

- name: Run pre-commit on changed files
if: github.event_name == 'pull_request'
run: pre-commit run --from-ref origin/${{ github.base_ref }} --to-ref ${{ github.head_ref }}

# ============================================================
# Job 2: 代码复杂度分析
# ============================================================
complexity:
name: Complexity Analysis
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: "pip"

- name: Install dependencies
run: pip install radon wily

- name: Run Radon complexity analysis
run: |
radon cc -a -i ".venv,tests" . || true
continue-on-error: true

- name: Run Wily complexity tracking
run: |
wily graph . --output wily-report || true
wily report . --metric loc --output wily-loc.txt || true
continue-on-error: true

- name: Upload complexity reports
uses: actions/upload-artifact@v4
if: always()
with:
name: complexity-reports
path: wily-loc.txt
retention-days: 7
if-no-files-found: ignore

# ============================================================
# Job 3: 依赖审计
# ============================================================
dependency-audit:
name: Dependency Audit
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: "pip"

- name: Install pip-audit
run: pip install pip-audit

- name: Run pip-audit
run: pip-audit -r requirements.txt --format=json --output=pip-audit.json || true
continue-on-error: true

- name: Upload pip-audit report
uses: actions/upload-artifact@v4
if: always()
with:
name: pip-audit-report
path: pip-audit.json
retention-days: 30
if-no-files-found: ignore

# ============================================================
# Job 4: 过期依赖检查
# ============================================================
outdated-deps:
name: Outdated Dependencies
runs-on: ubuntu-latest
timeout-minutes: 5

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: "pip"

- name: Check outdated dependencies
run: pip install pipdate && pipdate --diff 2>&1 || true
continue-on-error: true
Loading