- CI: awoooi-ci service with sha + ci environment - CD: awoooi-cd service with sha + production environment - Exports to SignOz at 192.168.0.121:4318 Approved: 2026-03-24 統帥指令 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
265 lines
7.2 KiB
YAML
265 lines
7.2 KiB
YAML
# =============================================================================
|
|
# AWOOOI CI Pipeline v2.0 (沿用 AIOPS 最佳實踐)
|
|
# =============================================================================
|
|
|
|
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
branches: [main]
|
|
workflow_dispatch:
|
|
|
|
concurrency:
|
|
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
NODE_VERSION: '20'
|
|
PNPM_VERSION: '9'
|
|
PYTHON_VERSION: '3.11'
|
|
# OTEL CI/CD 監控 (2026-03-24 批准)
|
|
OTEL_EXPORTER_OTLP_ENDPOINT: http://192.168.0.121:4318
|
|
OTEL_SERVICE_NAME: awoooi-ci
|
|
OTEL_RESOURCE_ATTRIBUTES: service.version=${{ github.sha }},deployment.environment=ci
|
|
|
|
jobs:
|
|
# ==================== Pre-flight (10s Fail-Fast) ====================
|
|
pre-flight:
|
|
name: "Pre-flight"
|
|
runs-on: [self-hosted, harbor, k8s]
|
|
timeout-minutes: 1
|
|
steps:
|
|
- name: Quick sanity check
|
|
run: |
|
|
echo "✅ Runner 可用"
|
|
node --version || echo "⚠️ Node not found"
|
|
python3 --version || echo "⚠️ Python not found"
|
|
|
|
# ==================== Lint & Type Check ====================
|
|
lint:
|
|
name: Lint & Type Check
|
|
runs-on: [self-hosted, harbor, k8s]
|
|
needs: pre-flight
|
|
timeout-minutes: 10
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@v3
|
|
with:
|
|
version: ${{ env.PNPM_VERSION }}
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: 'pnpm'
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Lint
|
|
run: pnpm lint
|
|
|
|
- name: Type check
|
|
run: pnpm typecheck
|
|
|
|
- name: ADR Compliance Check
|
|
run: |
|
|
echo "🔍 檢查 ADR 規定..."
|
|
# 檢查 1: 前端禁止直連資料庫 (ADR-005)
|
|
if grep -rE "psycopg2|asyncpg|redis|sqlalchemy|pg|ioredis" apps/web/src/ 2>/dev/null; then
|
|
echo "❌ ADR-005 違規: 前端禁止直連資料庫"
|
|
exit 1
|
|
fi
|
|
# 檢查 2: 禁止 Redux (ADR-004)
|
|
if grep -rE "@reduxjs/toolkit|react-redux" apps/web/package.json 2>/dev/null; then
|
|
echo "❌ ADR-004 違規: 禁止 Redux"
|
|
exit 1
|
|
fi
|
|
# 檢查 3: 禁止 import 舊專案
|
|
if grep -rE "from ['\"].*wooo-aiops" apps/ packages/ 2>/dev/null; then
|
|
echo "❌ 禁止 import 舊專案"
|
|
exit 1
|
|
fi
|
|
echo "✅ ADR 檢查通過"
|
|
|
|
# ==================== Test ====================
|
|
test:
|
|
name: Test
|
|
runs-on: [self-hosted, harbor, k8s]
|
|
needs: lint
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@v3
|
|
with:
|
|
version: ${{ env.PNPM_VERSION }}
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: 'pnpm'
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Run tests
|
|
run: pnpm test
|
|
continue-on-error: true
|
|
|
|
- name: Upload coverage
|
|
uses: codecov/codecov-action@v4
|
|
with:
|
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
fail_ci_if_error: false
|
|
|
|
# ==================== Build ====================
|
|
build:
|
|
name: Build
|
|
runs-on: [self-hosted, harbor, k8s]
|
|
needs: lint
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@v3
|
|
with:
|
|
version: ${{ env.PNPM_VERSION }}
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: 'pnpm'
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Setup Turborepo Cache
|
|
uses: dtinth/setup-github-actions-caching-for-turbo@v1
|
|
|
|
- name: Build packages
|
|
env:
|
|
NEXT_PUBLIC_API_URL: https://awoooi.wooo.work
|
|
# 暫時停用前端 Sentry (會觸發區域網路權限對話框)
|
|
# TODO: 實作 Sentry Tunnel 後再啟用
|
|
# NEXT_PUBLIC_SENTRY_DSN: http://da02d4e5d6542e4d1ed6b2dd6542efeb@192.168.0.110:9000/2
|
|
run: pnpm turbo build
|
|
|
|
- name: Upload build artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: build-artifacts
|
|
path: |
|
|
apps/*/dist
|
|
packages/*/dist
|
|
retention-days: 7
|
|
|
|
# ==================== API Lint (Python) ====================
|
|
api-lint:
|
|
name: API Lint
|
|
runs-on: [self-hosted, harbor, k8s]
|
|
needs: pre-flight
|
|
timeout-minutes: 5
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Setup Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v3
|
|
|
|
- name: Install & Lint
|
|
working-directory: apps/api
|
|
run: |
|
|
uv sync
|
|
uv run ruff check .
|
|
|
|
- name: Type check
|
|
working-directory: apps/api
|
|
run: uv run mypy src/ --exclude 'tests/|scripts/' || true
|
|
continue-on-error: true
|
|
|
|
# ==================== API Test ====================
|
|
api-test:
|
|
name: API Test
|
|
runs-on: [self-hosted, harbor, k8s]
|
|
needs: api-lint
|
|
timeout-minutes: 10
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Setup Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v3
|
|
|
|
- name: Install & Test
|
|
working-directory: apps/api
|
|
env:
|
|
PYTHONPATH: ${{ github.workspace }}/apps/api
|
|
run: |
|
|
uv sync
|
|
uv run pytest tests/ --cov=src --cov-report=xml -v || true
|
|
continue-on-error: true
|
|
|
|
# ==================== OpenAPI Validation ====================
|
|
openapi-validate:
|
|
name: OpenAPI Validate
|
|
runs-on: [self-hosted, harbor, k8s]
|
|
needs: pre-flight
|
|
timeout-minutes: 3
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
|
|
- name: Validate
|
|
run: |
|
|
npm install -g @stoplight/spectral-cli
|
|
spectral lint docs/api/api-contract.yaml || true
|
|
|
|
# ==================== Docker Build Verify ====================
|
|
docker-build:
|
|
name: Docker Verify
|
|
runs-on: [self-hosted, harbor, k8s]
|
|
needs: [test, api-test, build]
|
|
timeout-minutes: 20
|
|
strategy:
|
|
matrix:
|
|
app: [web, api]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Build (no push)
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
context: .
|
|
file: apps/${{ matrix.app }}/Dockerfile
|
|
push: false
|
|
tags: awoooi-${{ matrix.app }}:test
|
|
build-args: |
|
|
NEXT_PUBLIC_API_URL=https://awoooi.wooo.work
|
|
NEXT_PUBLIC_SENTRY_DSN=http://da02d4e5d6542e4d1ed6b2dd6542efeb@192.168.0.110:9000/2
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|