ea172633bb
Synology act_runner v0.2.11에서 push 이벤트 시 'if: always() && github.event_name == pull_request' 조건이 스텝을 failure로 잘못 처리해 job conclusion이 failure로 오보됨. 실제 CI는 모든 검증 단계 통과(Job succeeded) 했으나 API가 failure 반환. always() 제거로 push 이벤트에서 스텝이 정상적으로 skip 처리됨. PR 이벤트에서만 알림 발송 (실패 시 알림 없음은 허용 가능한 트레이드오프). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
127 lines
5.3 KiB
YAML
127 lines
5.3 KiB
YAML
name: Quant Engine CI/CD Pipeline
|
|
|
|
on:
|
|
push:
|
|
branches: [ main ]
|
|
pull_request:
|
|
branches: [ main ]
|
|
|
|
# ─────────────────────────────────────────────────────────────────
|
|
# Synology DS216j (ARMv7l 32-bit) 환경 제약
|
|
# - Python: /usr/bin/python3 (3.8.12)
|
|
# - Node.js 18: /usr/local/bin (appstore)
|
|
# - numpy/pandas: 공식 휠 없음, gcc 미설치 → 소스 빌드 불가
|
|
#
|
|
# CI 역할: 코드 구조 검증 게이트 (순수 Python, yaml/json)
|
|
# - Validate Specs / Formula Registry / Coverage / Behavioral Coverage
|
|
# 통합 테스트(run_release_dag, ingest 등)는 로컬에서 실행
|
|
# ─────────────────────────────────────────────────────────────────
|
|
|
|
jobs:
|
|
validate-and-build:
|
|
runs-on: self-hosted
|
|
|
|
steps:
|
|
- name: Checkout Code
|
|
run: |
|
|
if [ -d .git ]; then
|
|
git remote set-url origin http://x-access-token:${{ secrets.GITHUB_TOKEN }}@192.168.123.100:8418/KimJaeHyun/myfinance.git
|
|
else
|
|
git init
|
|
git remote add origin http://x-access-token:${{ secrets.GITHUB_TOKEN }}@192.168.123.100:8418/KimJaeHyun/myfinance.git
|
|
fi
|
|
git fetch origin ${{ github.sha }} --depth=1
|
|
git reset --hard FETCH_HEAD
|
|
|
|
- name: Configure Runtime Paths
|
|
run: |
|
|
# Node.js 18: /usr/local/bin (appstore symlink)
|
|
export PATH=/usr/local/bin:$PATH
|
|
echo "/usr/local/bin" >> $GITHUB_PATH
|
|
echo "=== 런타임 확인 ==="
|
|
/usr/bin/python3 --version
|
|
node --version
|
|
npm --version
|
|
|
|
- name: Setup Python Environment
|
|
run: |
|
|
# 순수 Python 패키지만 설치 (numpy/pandas 제외 — ARMv7l 휠 없음)
|
|
VENV=/volume1/gitea/python_venv
|
|
if ! "$VENV/bin/python" -c "import yaml, openpyxl" 2>/dev/null; then
|
|
echo "=== venv 생성 및 순수 Python 패키지 설치 ==="
|
|
[ ! -d "$VENV" ] && /usr/bin/python3 -m venv "$VENV"
|
|
|
|
# Synology Python 3.8은 ensurepip가 없어 venv 생성 시 pip가 누락될 수 있음
|
|
if [ ! -f "$VENV/bin/pip" ]; then
|
|
echo "pip missing in venv, installing via get-pip.py..."
|
|
curl -sS https://bootstrap.pypa.io/pip/3.8/get-pip.py -o get-pip.py
|
|
"$VENV/bin/python" get-pip.py --quiet
|
|
rm get-pip.py
|
|
fi
|
|
|
|
"$VENV/bin/pip" install --upgrade pip --quiet
|
|
"$VENV/bin/pip" install pyyaml openpyxl --quiet
|
|
if [ -f requirements.txt ]; then
|
|
# numpy/pandas/yfinance 계열은 건너뜀
|
|
grep -vE '^(numpy|pandas|scipy|yfinance|matplotlib)' requirements.txt \
|
|
| "$VENV/bin/pip" install -r /dev/stdin --quiet --prefer-binary 2>/dev/null || true
|
|
fi
|
|
echo "venv 설치 완료"
|
|
else
|
|
echo "=== venv 재사용: $("$VENV/bin/python" --version 2>&1) ==="
|
|
fi
|
|
echo "$VENV/bin" >> $GITHUB_PATH
|
|
|
|
- name: Install Node Dependencies
|
|
run: |
|
|
# package-lock.json 해시로 캐시 유효성 판단
|
|
CACHE_BASE=/volume1/gitea/node_cache
|
|
LOCK_HASH=$(md5sum package-lock.json 2>/dev/null | cut -d' ' -f1 || echo "no-lock")
|
|
[ -z "$LOCK_HASH" ] && LOCK_HASH="no-lock"
|
|
CACHE_DIR="$CACHE_BASE/$LOCK_HASH"
|
|
|
|
if [ -d "$CACHE_DIR/node_modules" ]; then
|
|
echo "=== node_modules 캐시 히트: $LOCK_HASH ==="
|
|
# 캐시에서 심볼릭 링크로 연결 (복사 대신 즉시)
|
|
rm -rf node_modules
|
|
ln -s "$CACHE_DIR/node_modules" node_modules
|
|
else
|
|
echo "=== npm install (최초 or lock 변경) ==="
|
|
npm install --quiet
|
|
# 캐시 저장
|
|
mkdir -p "$CACHE_DIR"
|
|
cp -r node_modules "$CACHE_DIR/node_modules"
|
|
echo "캐시 저장 완료: $CACHE_DIR"
|
|
# 오래된 캐시 정리 (최근 3개만 유지)
|
|
ls -dt "$CACHE_BASE"/*/ 2>/dev/null | tail -n +4 | xargs rm -rf 2>/dev/null || true
|
|
fi
|
|
node --version && npm --version
|
|
|
|
- name: Validate Specs
|
|
run: python3 tools/validate_specs.py
|
|
|
|
- name: Validate Formula Registry
|
|
run: python3 tools/validate_formula_registry.py
|
|
|
|
- name: Validate Golden Case Coverage
|
|
run: python3 tools/validate_golden_coverage_100.py
|
|
|
|
- name: Validate Harness Coverage Audit
|
|
run: python3 tools/harness_coverage_auditor.py
|
|
|
|
- name: Notify PR Result
|
|
if: github.event_name == 'pull_request'
|
|
run: |
|
|
STATUS="${{ job.status }}"
|
|
PR_NUM="${{ github.event.pull_request.number }}"
|
|
RUN_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
|
if [ "$STATUS" = "success" ]; then
|
|
MSG="✅ **CI PASS** — spec/registry/coverage gate OK\n\n[워크플로우 로그](${RUN_URL})"
|
|
else
|
|
MSG="❌ **CI FAIL** — 로그 확인 필요\n\n[워크플로우 로그](${RUN_URL})"
|
|
fi
|
|
curl -s -X POST "${{ github.api_url }}/repos/${{ github.repository }}/issues/${PR_NUM}/comments" \
|
|
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"body\":\"${MSG}\"}"
|