Skip to content

chore: 测试 GitHub 推送权限(OAuth App 需组织授权) #443

chore: 测试 GitHub 推送权限(OAuth App 需组织授权)

chore: 测试 GitHub 推送权限(OAuth App 需组织授权) #443

Workflow file for this run

name: CI
on:
push:
pull_request:
workflow_dispatch:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
# ─────────────────────────────────────────────────────────────────────────
# Layer 0: Change detection (diff-based incremental)
# ─────────────────────────────────────────────────────────────────────────
detect-changes:
name: Detect changes
runs-on: ubuntu-latest
outputs:
run_frontend: ${{ steps.diff.outputs.run_frontend }}
run_api: ${{ steps.diff.outputs.run_api }}
run_agent_sdk: ${{ steps.diff.outputs.run_agent_sdk }}
run_docker: ${{ steps.diff.outputs.run_docker }}
run_worldweave: ${{ steps.diff.outputs.run_worldweave }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Diff and set outputs
id: diff
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo "run_frontend=true" >> "$GITHUB_OUTPUT"
echo "run_api=true" >> "$GITHUB_OUTPUT"
echo "run_agent_sdk=true" >> "$GITHUB_OUTPUT"
echo "run_docker=true" >> "$GITHUB_OUTPUT"
echo "run_worldweave=true" >> "$GITHUB_OUTPUT"
exit 0
fi
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
BASE="${{ github.event.pull_request.base.sha }}"
else
BASE="HEAD~1"
fi
if ! git rev-parse "$BASE" &>/dev/null; then
echo "run_frontend=true" >> "$GITHUB_OUTPUT"
echo "run_api=true" >> "$GITHUB_OUTPUT"
echo "run_agent_sdk=true" >> "$GITHUB_OUTPUT"
echo "run_docker=true" >> "$GITHUB_OUTPUT"
echo "run_worldweave=true" >> "$GITHUB_OUTPUT"
exit 0
fi
CHANGED=$(git diff --name-only "$BASE" HEAD 2>/dev/null || echo "")
# Frontend: frontend/**, root config that affects frontend
if echo "$CHANGED" | grep -qE '^frontend/|^vite\.config\.|^tsconfig\.json'; then
echo "run_frontend=true" >> "$GITHUB_OUTPUT"
else
echo "run_frontend=false" >> "$GITHUB_OUTPUT"
fi
# Backend API: backend/app/api, models, core, main, test_api
if echo "$CHANGED" | grep -qE '^backend/(app/api/|app/models/|app/core/|main\.py|tests/test_api\.py|tests/conftest\.py)'; then
echo "run_api=true" >> "$GITHUB_OUTPUT"
else
echo "run_api=false" >> "$GITHUB_OUTPUT"
fi
# Backend Agent SDK: agent, prompts, skills, test_agent_sdk
if echo "$CHANGED" | grep -qE '^backend/(app/agent/|app/prompts/|skills/|tests/test_agent_sdk\.py|tests/conftest\.py)'; then
echo "run_agent_sdk=true" >> "$GITHUB_OUTPUT"
else
echo "run_agent_sdk=false" >> "$GITHUB_OUTPUT"
fi
# Docker: docker-compose, Dockerfiles, deploy
if echo "$CHANGED" | grep -qE '^docker-compose\.(yml|yaml)|^\.github/workflows/deploy\.yml|^scripts/deploy-clawarcade-reviewer\.sh|/(Dockerfile([^/]+)?|\.dockerignore)'; then
echo "run_docker=true" >> "$GITHUB_OUTPUT"
else
echo "run_docker=false" >> "$GITHUB_OUTPUT"
fi
# WorldWeave: submodule pointer, deployment image, or same-origin proxy contract
if echo "$CHANGED" | grep -qE '^worldweave$|^docker/worldweave\.Dockerfile|^\.github/workflows/ci\.yml|^frontend/(nginx(\.root)?\.conf|nginx\.conf\.template|vite\.config\.ts|src/pages/(SourceFeedPage\.tsx|__tests__/(WorldWeaveProxyConfig|ViteWorldWeaveProxyConfig|SourceFeedPage)\.test\.(ts|tsx)))$'; then
echo "run_worldweave=true" >> "$GITHUB_OUTPUT"
else
echo "run_worldweave=false" >> "$GITHUB_OUTPUT"
fi
# ─────────────────────────────────────────────────────────────────────────
# Layer 1: Frontend build (compile + typecheck)
# ─────────────────────────────────────────────────────────────────────────
frontend-build:
name: Frontend build
needs: [detect-changes]
if: needs.detect-changes.outputs.run_frontend == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: frontend/package-lock.json
- name: Install and build
run: |
cd frontend
npm ci
npm run build
# ─────────────────────────────────────────────────────────────────────────
# Layer 1: Frontend WorldWeave contract tests
# ─────────────────────────────────────────────────────────────────────────
frontend-worldweave-tests:
name: Frontend WorldWeave tests
needs: [detect-changes]
if: needs.detect-changes.outputs.run_worldweave == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: frontend/package-lock.json
- name: Run focused WorldWeave frontend tests
run: |
cd frontend
npm ci
npm test -- --run \
src/pages/__tests__/WorldWeaveProxyConfig.test.ts \
src/pages/__tests__/ViteWorldWeaveProxyConfig.test.ts \
src/pages/__tests__/SourceFeedPage.test.tsx
# ─────────────────────────────────────────────────────────────────────────
# Layer 1: WorldWeave unit tests and build
# ─────────────────────────────────────────────────────────────────────────
worldweave-checks:
name: WorldWeave checks
needs: [detect-changes]
if: needs.detect-changes.outputs.run_worldweave == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Enable pnpm
working-directory: worldweave
run: |
corepack enable
corepack prepare pnpm@9.0.0 --activate
- name: Install dependencies
working-directory: worldweave
run: pnpm install --frozen-lockfile
- name: Run unit tests
working-directory: worldweave
run: pnpm run test
- name: Type check
working-directory: worldweave
run: pnpm run ts-check
- name: Build
working-directory: worldweave
run: pnpm run build
# ─────────────────────────────────────────────────────────────────────────
# Layer 1: Backend unit tests (API)
# ─────────────────────────────────────────────────────────────────────────
unit-tests-api:
name: Unit (API)
needs: [detect-changes]
if: needs.detect-changes.outputs.run_api == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup uv
uses: astral-sh/setup-uv@v5
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Run API unit tests
working-directory: backend
run: |
echo "=== Unit tests: API (topics, posts, experts) ==="
uv run \
--with fastapi --with uvicorn --with pydantic --with pydantic-settings \
--with python-dotenv --with claude-agent-sdk --with anthropic --with openai \
--with pytest --with pytest-asyncio --with httpx \
pytest tests/test_api.py -v --tb=short
# ─────────────────────────────────────────────────────────────────────────
# Layer 1: Backend unit tests (Agent SDK, mocked)
# ─────────────────────────────────────────────────────────────────────────
unit-tests-agent-sdk:
name: Unit (Agent SDK)
needs: [detect-changes]
if: needs.detect-changes.outputs.run_agent_sdk == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup uv
uses: astral-sh/setup-uv@v5
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Run Agent SDK unit tests (mocked)
working-directory: backend
run: |
echo "=== Unit tests: Agent SDK (not integration) ==="
uv run \
--with fastapi --with uvicorn --with pydantic --with pydantic-settings \
--with python-dotenv --with claude-agent-sdk --with anthropic --with openai \
--with pytest --with pytest-asyncio --with httpx \
pytest tests/test_agent_sdk.py -m "not integration" -v --tb=short
# ─────────────────────────────────────────────────────────────────────────
# Layer 2: Integration tests (Agent SDK, real API)
# Requires ANTHROPIC_API_KEY; skipped if not configured
# ─────────────────────────────────────────────────────────────────────────
integration-tests-agent-sdk:
name: Integration (Agent SDK)
needs: [detect-changes, unit-tests-agent-sdk]
if: needs.detect-changes.outputs.run_agent_sdk == 'true'
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Check ANTHROPIC_API_KEY
id: check_key
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
if [[ -z "${ANTHROPIC_API_KEY:-}" || "${ANTHROPIC_API_KEY}" == "test" ]]; then
echo "::notice title=Integration skipped::ANTHROPIC_API_KEY not configured; job skipped (success)"
echo "has_key=false" >> "$GITHUB_OUTPUT"
else
echo "has_key=true" >> "$GITHUB_OUTPUT"
fi
- uses: actions/checkout@v4
if: steps.check_key.outputs.has_key == 'true'
with:
submodules: recursive
- name: Setup uv
if: steps.check_key.outputs.has_key == 'true'
uses: astral-sh/setup-uv@v5
- name: Setup Python
if: steps.check_key.outputs.has_key == 'true'
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Run Agent SDK integration tests
if: steps.check_key.outputs.has_key == 'true'
working-directory: backend
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
uv run \
--with fastapi --with uvicorn --with pydantic --with pydantic-settings \
--with python-dotenv --with claude-agent-sdk --with anthropic --with openai \
--with pytest --with pytest-asyncio --with httpx \
pytest tests/test_agent_sdk.py -m integration -v --tb=short
# ─────────────────────────────────────────────────────────────────────────
# Layer 1: Docker build (validates deploy pipeline)
# ─────────────────────────────────────────────────────────────────────────
docker-build:
name: Docker build
needs: [detect-changes]
if: needs.detect-changes.outputs.run_docker == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Build images
run: |
docker compose build --no-cache