Skip to content

feat(T007/phase3): 엔드투엔드 양도세 신고 CLI (scripts/run_tax_report.py) #11

feat(T007/phase3): 엔드투엔드 양도세 신고 CLI (scripts/run_tax_report.py)

feat(T007/phase3): 엔드투엔드 양도세 신고 CLI (scripts/run_tax_report.py) #11

Workflow file for this run

name: CI
on:
push:
branches: [master, main, "feature/**"]
pull_request:
branches: [master, main]
permissions:
contents: read
jobs:
lint-and-test:
name: ruff + pytest (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.12"]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: pyproject.toml
- name: Install package (dev extras)
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"
- name: ruff check
run: ruff check sentinelq/ tests/
- name: ruff format --check
run: ruff format --check sentinelq/ tests/
- name: pytest with coverage
run: |
pytest tests/ -v \
--cov=sentinelq.tax \
--cov=sentinelq.portfolio \
--cov-report=term-missing \
--cov-report=xml \
-m "not integration"
- name: Enforce baseline.json regression floor
# baseline.json의 test.total을 회귀 차단 floor로 사용한다.
# 수집된 테스트(passed + skipped)가 total 미만이면 실패 (테스트 유실 회귀).
# skip은 skip_tolerance 이내까지 허용 (예: KIS cache 부재로 인한 합법적 skip).
run: |
python - <<'PY'
import json, subprocess, sys, re
baseline = json.load(open(".claude/baseline.json"))
total_floor = baseline["test"]["total"]
skip_tol = baseline["test"].get("skip_tolerance", 0)
result = subprocess.run(
["pytest", "tests/", "-q", "-m", "not integration", "--no-header"],
capture_output=True, text=True
)
output = result.stdout + result.stderr
passed = int(re.search(r"(\d+) passed", output).group(1)) if re.search(r"(\d+) passed", output) else 0
skipped_m = re.search(r"(\d+) skipped", output)
skipped = int(skipped_m.group(1)) if skipped_m else 0
failed_m = re.search(r"(\d+) failed", output)
failed = int(failed_m.group(1)) if failed_m else 0
collected = passed + skipped + failed
print(f"baseline: total={total_floor}, skip_tol={skip_tol}")
print(f"current : passed={passed}, skipped={skipped}, failed={failed}, collected={collected}")
ok = True
if failed > 0:
print(f"::error::Test failures: {failed}")
ok = False
if collected < total_floor:
print(f"::error::Regression: collected {collected} < baseline total {total_floor} (테스트 유실)")
ok = False
if skipped > skip_tol:
print(f"::error::Too many skips: {skipped} > tolerance {skip_tol}")
ok = False
if not ok:
sys.exit(1)
print("OK: at or above baseline floor.")
PY
- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-${{ matrix.python-version }}
path: coverage.xml
if-no-files-found: ignore
secrets-scan:
name: gitleaks secrets scan
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_CONFIG: .gitleaks.toml