|
25123
|
18561
|
6
|
5
|
3852c841f557d197a777c094ed1243a8198cdf8e
|
0
|
Frontend Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
frontend-typecheck:
name: Frontend Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Build shared package
run: pnpm -C shared run build
- name: 前端类型检查(vue-tsc --noEmit)
run: pnpm --filter ./frontend run type-check
permissions:
contents: read
...
|
frontend-typecheck
|
null
|
["ubuntu-latest"]
|
21523
|
2
|
1777426590
|
1777426681
|
1777426588
|
1777426681
|
|
0
|
|
0
|
Edit
Delete
|
|
25124
|
18561
|
6
|
5
|
3852c841f557d197a777c094ed1243a8198cdf8e
|
0
|
Lint & Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Backend type check
run: pnpm -C backend run type-check
- name: Lint
run: pnpm -C backend run lint
permissions:
contents: read
...
|
lint-and-typecheck
|
null
|
["ubuntu-latest"]
|
21524
|
2
|
1777426681
|
1777426772
|
1777426588
|
1777426772
|
|
0
|
|
0
|
Edit
Delete
|
|
25130
|
18562
|
6
|
5
|
3852c841f557d197a777c094ed1243a8198cdf8e
|
0
|
full-test-suite (chromium)
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
full-test-suite:
name: full-test-suite (chromium)
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'all')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build backend
run: |
cd backend
npm run build
- name: Build frontend
run: |
cd frontend
npm run build
- name: Install Playwright Browsers
run: npx playwright install --with-deps ${{ matrix.browser }}
- name: Start backend server
run: |
cd backend
npm run start &
sleep 10
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
- name: Start frontend server
run: |
cd frontend
npm run preview &
sleep 5
env:
VITE_API_URL: http://localhost:3000
- name: Run all E2E tests
run: |
cd e2e
npx playwright test --project=${{ matrix.browser }} --reporter=html,json
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload test results
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.browser }}
path: e2e/playwright-report/
retention-days: "30"
- if: always()
name: Upload test artifacts
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.browser }}
path: e2e/test-results/
retention-days: "30"
timeout-minutes: "60"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
browser:
- chromium
...
|
full-test-suite
|
null
|
["ubuntu-latest"]
|
21526
|
2
|
1777426775
|
1777426866
|
1777426589
|
1777426866
|
|
0
|
|
0
|
Edit
Delete
|
|
25131
|
18562
|
6
|
5
|
3852c841f557d197a777c094ed1243a8198cdf8e
|
0
|
full-test-suite (firefox)
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
full-test-suite:
name: full-test-suite (firefox)
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'all')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build backend
run: |
cd backend
npm run build
- name: Build frontend
run: |
cd frontend
npm run build
- name: Install Playwright Browsers
run: npx playwright install --with-deps ${{ matrix.browser }}
- name: Start backend server
run: |
cd backend
npm run start &
sleep 10
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
- name: Start frontend server
run: |
cd frontend
npm run preview &
sleep 5
env:
VITE_API_URL: http://localhost:3000
- name: Run all E2E tests
run: |
cd e2e
npx playwright test --project=${{ matrix.browser }} --reporter=html,json
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload test results
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.browser }}
path: e2e/playwright-report/
retention-days: "30"
- if: always()
name: Upload test artifacts
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.browser }}
path: e2e/test-results/
retention-days: "30"
timeout-minutes: "60"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
browser:
- firefox
...
|
full-test-suite
|
null
|
["ubuntu-latest"]
|
21527
|
2
|
1777426866
|
1777426957
|
1777426589
|
1777426957
|
|
0
|
|
0
|
Edit
Delete
|
|
25132
|
18562
|
6
|
5
|
3852c841f557d197a777c094ed1243a8198cdf8e
|
0
|
full-test-suite (webkit)
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
full-test-suite:
name: full-test-suite (webkit)
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'all')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build backend
run: |
cd backend
npm run build
- name: Build frontend
run: |
cd frontend
npm run build
- name: Install Playwright Browsers
run: npx playwright install --with-deps ${{ matrix.browser }}
- name: Start backend server
run: |
cd backend
npm run start &
sleep 10
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
- name: Start frontend server
run: |
cd frontend
npm run preview &
sleep 5
env:
VITE_API_URL: http://localhost:3000
- name: Run all E2E tests
run: |
cd e2e
npx playwright test --project=${{ matrix.browser }} --reporter=html,json
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload test results
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.browser }}
path: e2e/playwright-report/
retention-days: "30"
- if: always()
name: Upload test artifacts
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.browser }}
path: e2e/test-results/
retention-days: "30"
timeout-minutes: "60"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
browser:
- webkit
...
|
full-test-suite
|
null
|
["ubuntu-latest"]
|
21528
|
2
|
1777426957
|
1777426976
|
1777426589
|
1777426977
|
|
0
|
|
0
|
Edit
Delete
|
|
25135
|
18562
|
6
|
5
|
3852c841f557d197a777c094ed1243a8198cdf8e
|
0
|
visual-regression
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
visual-regression:
name: visual-regression
runs-on: ubuntu-latest
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'visual-regression')
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build and start services
run: |
cd backend && npm run build && npm run start &
cd frontend && npm run build && npm run preview &
sleep 15
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
VITE_API_URL: http://localhost:3000
- name: Install Playwright
run: npx playwright install --with-deps chromium
- name: Run visual regression tests
run: |
cd e2e
npx playwright test tests/visual-regression/ --reporter=html
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload visual diff results
uses: actions/upload-artifact@v4
with:
name: visual-regression-report
path: |
e2e/playwright-report/
e2e/test-results/
retention-days: "30"
- if: github.event_name == 'push' && github.ref == 'refs/heads/main'
name: Update baseline screenshots
run: |
cd e2e
npx playwright test tests/visual-regression/ --update-snapshots
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git add tests/visual-regression/**/*.png
git commit -m "chore: update visual regression baselines" || echo "No changes"
git push
timeout-minutes: "30"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
...
|
visual-regression
|
null
|
["ubuntu-latest"]
|
21531
|
2
|
1777426981
|
1777427064
|
1777426589
|
1777427065
|
|
0
|
|
0
|
Edit
Delete
|
|
25136
|
18562
|
6
|
5
|
3852c841f557d197a777c094ed1243a8198cdf8e
|
0
|
test-summary
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
test-summary:
name: test-summary
runs-on: ubuntu-latest
if: always()
steps:
- name: Download all test artifacts
uses: actions/download-artifact@v4
- name: Generate summary report
run: "echo \"## \U0001F9EA E2E 测试汇总\" >> $GITHUB_STEP_SUMMARY\necho \"\" >> $GITHUB_STEP_SUMMARY\n\nif [ -d \"playwright-report-pr\" ]; then\n echo \"### PR 快速验证\" >> $GITHUB_STEP_SUMMARY\n echo \"✅ 关键测试通过\" >> $GITHUB_STEP_SUMMARY\nfi\n\nif [ -d \"business-flows-report\" ]; then\n echo \"### 业务流程测试\" >> $GITHUB_STEP_SUMMARY\n echo \"✅ 业务流程测试完成\" >> $GITHUB_STEP_SUMMARY\nfi\n\nif [ -d \"performance-report\" ]; then\n echo \"### 性能基准测试\" >> $GITHUB_STEP_SUMMARY\n echo \"\U0001F4CA 性能测试报告已生成\" >> $GITHUB_STEP_SUMMARY\nfi\n\nif [ -d \"visual-regression-report\" ]; then\n echo \"### 视觉回归测试\" >> $GITHUB_STEP_SUMMARY\n echo \"\U0001F3A8 视觉对比完成\" >> $GITHUB_STEP_SUMMARY\nfi\n"
...
|
test-summary
|
["pr-validation","full-test-suite" ["pr-validation","full-test-suite","business-flows","performance-benchmarks","visual-regression"]...
|
["ubuntu-latest"]
|
21537
|
2
|
1777427171
|
1777427261
|
1777426589
|
1777427261
|
|
1
|
|
0
|
Edit
Delete
|
|
25137
|
18563
|
6
|
5
|
3852c841f557d197a777c094ed1243a8198cdf8e
|
0
|
migration-safety
|
1
|
name: Database Migration Safety Check
"on" name: Database Migration Safety Check
"on":
push:
paths:
- 'backend/prisma/migrations/**'
- 'backend/prisma/schema.prisma'
- 'backend/prisma/schema/**'
pull_request:
paths:
- 'backend/prisma/migrations/**'
- 'backend/prisma/schema.prisma'
- 'backend/prisma/schema/**'
jobs:
migration-safety:
name: migration-safety
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: "20"
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: "8"
- name: Install dependencies
run: pnpm install --frozen-lockfile
working-directory: ./backend
- name: Verify Prisma schema mirror
run: pnpm run audit:prisma-schema-source
working-directory: ./backend
- name: Create PostgreSQL extensions on deploy DB
run: |
# 主部署库
psql -h localhost -U juhi -d juhi_revops_test -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"
psql -h localhost -U juhi -d juhi_revops_test -c "CREATE EXTENSION IF NOT EXISTS pgcrypto;"
psql -h localhost -U juhi -d juhi_revops_test -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"
psql -h localhost -U juhi -d juhi_revops_test -c "CREATE EXTENSION IF NOT EXISTS vector;"
env:
PGPASSWORD: test_password
- name: Create shadow DB for prisma migrate diff
run: |
# prisma migrate diff 在 ephemeral shadow DB 上 replay 历史 migrations,
# 然后与 prisma/schema 文件夹真源对比生成 drift SQL。必须是独立空库,不能用 deploy DB
psql -h localhost -U juhi -d postgres -c "CREATE DATABASE juhi_shadow_test;"
psql -h localhost -U juhi -d juhi_shadow_test -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"
psql -h localhost -U juhi -d juhi_shadow_test -c "CREATE EXTENSION IF NOT EXISTS pgcrypto;"
psql -h localhost -U juhi -d juhi_shadow_test -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"
psql -h localhost -U juhi -d juhi_shadow_test -c "CREATE EXTENSION IF NOT EXISTS vector;"
env:
PGPASSWORD: test_password
- name: Run migration safety checks
run: |
# Run the comprehensive migration safety check
./scripts/ci-migration-check.sh
env:
DATABASE_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
DIRECT_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
- name: Validate Prisma schema
run: |
npx prisma validate
working-directory: ./backend
env:
DATABASE_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
- name: Generate Prisma Client
run: |
npx prisma generate
working-directory: ./backend
env:
DATABASE_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
- name: Migration deploy gate (HARD)
run: |
./scripts/ci-migration-deploy-gate.sh
env:
DATABASE_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
DIRECT_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
SHADOW_DATABASE_URL: postgresql://juhi:test_password@localhost:5432/juhi_shadow_test
- if: always()
name: Upload migration drift artifacts
uses: actions/upload-artifact@v4
with:
if-no-files-found: warn
name: migration-drift-reports
path: |
reports/migration-drift-diff.latest.sql
reports/migration-drift-summary.latest.json
retention-days: "14"
services:
postgres:
image: pgvector/pgvector:pg16
env:
POSTGRES_DB: juhi_revops_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: juhi
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
...
|
migration-safety
|
null
|
["ubuntu-latest"]
|
21532
|
2
|
1777427072
|
1777427102
|
1777426590
|
1777427102
|
|
0
|
|
0
|
Edit
Delete
|
|
25138
|
18564
|
6
|
5
|
3852c841f557d197a777c094ed1243a8198cdf8e
|
0
|
检测代码变更
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
detect-changes:
name: 检测代码变更
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: filter
uses: dorny/paths-filter@v3
with:
filters: |
backend:
- 'backend/**'
- 'shared/**'
frontend:
- 'frontend/**'
- 'shared/**'
shared:
- 'shared/**'
ai-modules:
- 'backend/src/modules/ai-agents/**'
- 'backend/src/modules/ai-agent-skills/**'
- 'backend/src/modules/ai-review-queue/**'
- 'backend/src/modules/ai-copilot/**'
- 'backend/src/modules/lead-scoring-ai/**'
- 'backend/src/shared/state-machines/machines/ai-*.ts'
- 'backend/src/shared/state-machines/machines/training-*.ts'
prisma:
- 'backend/prisma/**'
e2e:
- 'e2e/**'
outputs:
ai-modules: ${{ steps.filter.outputs.ai-modules }}
backend: ${{ steps.filter.outputs.backend }}
e2e: ${{ steps.filter.outputs.e2e }}
frontend: ${{ steps.filter.outputs.frontend }}
prisma: ${{ steps.filter.outputs.prisma }}
shared: ${{ steps.filter.outputs.shared }}
...
|
detect-changes
|
null
|
["ubuntu-latest"]
|
21533
|
2
|
1777427103
|
1777427133
|
1777426591
|
1777427133
|
|
0
|
|
0
|
Edit
Delete
|
|
25139
|
18564
|
6
|
5
|
3852c841f557d197a777c094ed1243a8198cdf8e
|
0
|
安装依赖
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
setup:
name: 安装依赖
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 缓存依赖
uses: actions/cache/save@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
...
|
setup
|
null
|
["ubuntu-latest"]
|
21534
|
2
|
1777427134
|
1777427164
|
1777426591
|
1777427164
|
|
0
|
|
0
|
Edit
Delete
|
|
25159
|
18564
|
6
|
5
|
3852c841f557d197a777c094ed1243a8198cdf8e
|
0
|
覆盖率报告合并
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
coverage-report:
name: 覆盖率报告合并
runs-on: ubuntu-latest
if: always() && !cancelled()
steps:
- uses: actions/checkout@v4
- name: 下载所有覆盖率报告
uses: actions/download-artifact@v4
with:
merge-multiple: "true"
path: coverage-reports
pattern: '*-coverage'
- name: 上传到 Codecov
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: "false"
files: coverage-reports/**/*.info
verbose: "true"
...
|
coverage-report
|
["backend-unit-test","frontend-unit-te ["backend-unit-test","frontend-unit-test","shared-check"]...
|
["ubuntu-latest"]
|
21555
|
2
|
1777427393
|
1777427413
|
1777426591
|
1777427414
|
|
1
|
|
0
|
Edit
Delete
|
|
25162
|
18566
|
6
|
5
|
3852c841f557d197a777c094ed1243a8198cdf8e
|
0
|
📥 收集测试结果
|
1
|
name: Test Report
"on":
workflow_run:
name: Test Report
"on":
workflow_run:
workflows:
- 'Test Suite'
- 'E2E Tests'
- 'Performance Tests'
types:
- completed
env:
NODE_VERSION: "18"
jobs:
collect-results:
name: "\U0001F4E5 收集测试结果"
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion != 'cancelled'
steps:
- name: "\U0001F4DD 记录工作流信息"
run: |
echo "工作流: ${{ github.event.workflow_run.name }}"
echo "结果: ${{ github.event.workflow_run.conclusion }}"
echo "运行 ID: ${{ github.event.workflow_run.id }}"
echo "分支: ${{ github.event.workflow_run.head_branch }}"
- name: "\U0001F4E5 下载测试结果 artifacts"
uses: actions/github-script@v7
with:
script: |
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
console.log('找到的 artifacts:');
for (const artifact of artifacts.data.artifacts) {
console.log(`- ${artifact.name} (${artifact.size_in_bytes} bytes)`);
}
// 保存 artifact 列表
const fs = require('fs');
fs.writeFileSync('artifacts.json', JSON.stringify(artifacts.data.artifacts, null, 2));
- name: "\U0001F4E4 上传 artifact 清单"
uses: actions/upload-artifact@v4
with:
name: artifact-list-${{ github.event.workflow_run.id }}
path: artifacts.json
retention-days: "7"
outputs:
run_id: ${{ github.event.workflow_run.id }}
workflow_conclusion: ${{ github.event.workflow_run.conclusion }}
workflow_name: ${{ github.event.workflow_run.name }}
...
|
collect-results
|
null
|
["ubuntu-latest"]
|
21538
|
2
|
1777427262
|
1777427353
|
1777427071
|
1777427353
|
|
0
|
|
0
|
Edit
Delete
|
|
25177
|
18569
|
6
|
5
|
3852c841f557d197a777c094ed1243a8198cdf8e
|
0
|
📥 收集测试结果
|
1
|
name: Test Report
"on":
workflow_run:
name: Test Report
"on":
workflow_run:
workflows:
- 'Test Suite'
- 'E2E Tests'
- 'Performance Tests'
types:
- completed
env:
NODE_VERSION: "18"
jobs:
collect-results:
name: "\U0001F4E5 收集测试结果"
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion != 'cancelled'
steps:
- name: "\U0001F4DD 记录工作流信息"
run: |
echo "工作流: ${{ github.event.workflow_run.name }}"
echo "结果: ${{ github.event.workflow_run.conclusion }}"
echo "运行 ID: ${{ github.event.workflow_run.id }}"
echo "分支: ${{ github.event.workflow_run.head_branch }}"
- name: "\U0001F4E5 下载测试结果 artifacts"
uses: actions/github-script@v7
with:
script: |
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
console.log('找到的 artifacts:');
for (const artifact of artifacts.data.artifacts) {
console.log(`- ${artifact.name} (${artifact.size_in_bytes} bytes)`);
}
// 保存 artifact 列表
const fs = require('fs');
fs.writeFileSync('artifacts.json', JSON.stringify(artifacts.data.artifacts, null, 2));
- name: "\U0001F4E4 上传 artifact 清单"
uses: actions/upload-artifact@v4
with:
name: artifact-list-${{ github.event.workflow_run.id }}
path: artifacts.json
retention-days: "7"
outputs:
run_id: ${{ github.event.workflow_run.id }}
workflow_conclusion: ${{ github.event.workflow_run.conclusion }}
workflow_name: ${{ github.event.workflow_run.name }}
...
|
collect-results
|
null
|
["ubuntu-latest"]
|
21545
|
2
|
1777427370
|
1777427374
|
1777427262
|
1777427375
|
|
0
|
|
0
|
Edit
Delete
|
|
25223
|
18585
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
Frontend Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
frontend-typecheck:
name: Frontend Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Build shared package
run: pnpm -C shared run build
- name: 前端类型检查(vue-tsc --noEmit)
run: pnpm --filter ./frontend run type-check
permissions:
contents: read
...
|
frontend-typecheck
|
null
|
["ubuntu-latest"]
|
21583
|
2
|
1777430952
|
1777431043
|
1777430950
|
1777431043
|
|
0
|
|
0
|
Edit
Delete
|
|
25224
|
18585
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
Lint & Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Backend type check
run: pnpm -C backend run type-check
- name: Lint
run: pnpm -C backend run lint
permissions:
contents: read
...
|
lint-and-typecheck
|
null
|
["ubuntu-latest"]
|
21584
|
2
|
1777431043
|
1777431074
|
1777430950
|
1777431074
|
|
0
|
|
0
|
Edit
Delete
|
|
25230
|
18586
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
full-test-suite (chromium)
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
full-test-suite:
name: full-test-suite (chromium)
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'all')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build backend
run: |
cd backend
npm run build
- name: Build frontend
run: |
cd frontend
npm run build
- name: Install Playwright Browsers
run: npx playwright install --with-deps ${{ matrix.browser }}
- name: Start backend server
run: |
cd backend
npm run start &
sleep 10
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
- name: Start frontend server
run: |
cd frontend
npm run preview &
sleep 5
env:
VITE_API_URL: http://localhost:3000
- name: Run all E2E tests
run: |
cd e2e
npx playwright test --project=${{ matrix.browser }} --reporter=html,json
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload test results
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.browser }}
path: e2e/playwright-report/
retention-days: "30"
- if: always()
name: Upload test artifacts
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.browser }}
path: e2e/test-results/
retention-days: "30"
timeout-minutes: "60"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
browser:
- chromium
...
|
full-test-suite
|
null
|
["ubuntu-latest"]
|
21586
|
2
|
1777431078
|
1777431108
|
1777430951
|
1777431109
|
|
0
|
|
0
|
Edit
Delete
|
|
25231
|
18586
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
full-test-suite (firefox)
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
full-test-suite:
name: full-test-suite (firefox)
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'all')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build backend
run: |
cd backend
npm run build
- name: Build frontend
run: |
cd frontend
npm run build
- name: Install Playwright Browsers
run: npx playwright install --with-deps ${{ matrix.browser }}
- name: Start backend server
run: |
cd backend
npm run start &
sleep 10
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
- name: Start frontend server
run: |
cd frontend
npm run preview &
sleep 5
env:
VITE_API_URL: http://localhost:3000
- name: Run all E2E tests
run: |
cd e2e
npx playwright test --project=${{ matrix.browser }} --reporter=html,json
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload test results
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.browser }}
path: e2e/playwright-report/
retention-days: "30"
- if: always()
name: Upload test artifacts
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.browser }}
path: e2e/test-results/
retention-days: "30"
timeout-minutes: "60"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
browser:
- firefox
...
|
full-test-suite
|
null
|
["ubuntu-latest"]
|
21587
|
2
|
1777431109
|
1777431139
|
1777430951
|
1777431139
|
|
0
|
|
0
|
Edit
Delete
|
|
25232
|
18586
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
full-test-suite (webkit)
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
full-test-suite:
name: full-test-suite (webkit)
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'all')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build backend
run: |
cd backend
npm run build
- name: Build frontend
run: |
cd frontend
npm run build
- name: Install Playwright Browsers
run: npx playwright install --with-deps ${{ matrix.browser }}
- name: Start backend server
run: |
cd backend
npm run start &
sleep 10
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
- name: Start frontend server
run: |
cd frontend
npm run preview &
sleep 5
env:
VITE_API_URL: http://localhost:3000
- name: Run all E2E tests
run: |
cd e2e
npx playwright test --project=${{ matrix.browser }} --reporter=html,json
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload test results
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.browser }}
path: e2e/playwright-report/
retention-days: "30"
- if: always()
name: Upload test artifacts
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.browser }}
path: e2e/test-results/
retention-days: "30"
timeout-minutes: "60"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
browser:
- webkit
...
|
full-test-suite
|
null
|
["ubuntu-latest"]
|
21588
|
2
|
1777431140
|
1777431170
|
1777430951
|
1777431170
|
|
0
|
|
0
|
Edit
Delete
|
|
25235
|
18586
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
visual-regression
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
visual-regression:
name: visual-regression
runs-on: ubuntu-latest
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'visual-regression')
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build and start services
run: |
cd backend && npm run build && npm run start &
cd frontend && npm run build && npm run preview &
sleep 15
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
VITE_API_URL: http://localhost:3000
- name: Install Playwright
run: npx playwright install --with-deps chromium
- name: Run visual regression tests
run: |
cd e2e
npx playwright test tests/visual-regression/ --reporter=html
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload visual diff results
uses: actions/upload-artifact@v4
with:
name: visual-regression-report
path: |
e2e/playwright-report/
e2e/test-results/
retention-days: "30"
- if: github.event_name == 'push' && github.ref == 'refs/heads/main'
name: Update baseline screenshots
run: |
cd e2e
npx playwright test tests/visual-regression/ --update-snapshots
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git add tests/visual-regression/**/*.png
git commit -m "chore: update visual regression baselines" || echo "No changes"
git push
timeout-minutes: "30"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
...
|
visual-regression
|
null
|
["ubuntu-latest"]
|
21591
|
2
|
1777431175
|
1777431265
|
1777430951
|
1777431265
|
|
0
|
|
0
|
Edit
Delete
|
|
25236
|
18586
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
test-summary
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
test-summary:
name: test-summary
runs-on: ubuntu-latest
if: always()
steps:
- name: Download all test artifacts
uses: actions/download-artifact@v4
- name: Generate summary report
run: "echo \"## \U0001F9EA E2E 测试汇总\" >> $GITHUB_STEP_SUMMARY\necho \"\" >> $GITHUB_STEP_SUMMARY\n\nif [ -d \"playwright-report-pr\" ]; then\n echo \"### PR 快速验证\" >> $GITHUB_STEP_SUMMARY\n echo \"✅ 关键测试通过\" >> $GITHUB_STEP_SUMMARY\nfi\n\nif [ -d \"business-flows-report\" ]; then\n echo \"### 业务流程测试\" >> $GITHUB_STEP_SUMMARY\n echo \"✅ 业务流程测试完成\" >> $GITHUB_STEP_SUMMARY\nfi\n\nif [ -d \"performance-report\" ]; then\n echo \"### 性能基准测试\" >> $GITHUB_STEP_SUMMARY\n echo \"\U0001F4CA 性能测试报告已生成\" >> $GITHUB_STEP_SUMMARY\nfi\n\nif [ -d \"visual-regression-report\" ]; then\n echo \"### 视觉回归测试\" >> $GITHUB_STEP_SUMMARY\n echo \"\U0001F3A8 视觉对比完成\" >> $GITHUB_STEP_SUMMARY\nfi\n"
...
|
test-summary
|
["pr-validation","full-test-suite" ["pr-validation","full-test-suite","business-flows","performance-benchmarks","visual-regression"]...
|
["ubuntu-latest"]
|
21597
|
2
|
1777432340
|
1777432342
|
1777430951
|
1777432343
|
|
1
|
|
0
|
Edit
Delete
|
|
25237
|
18587
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
检测代码变更
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
detect-changes:
name: 检测代码变更
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: filter
uses: dorny/paths-filter@v3
with:
filters: |
backend:
- 'backend/**'
- 'shared/**'
frontend:
- 'frontend/**'
- 'shared/**'
shared:
- 'shared/**'
ai-modules:
- 'backend/src/modules/ai-agents/**'
- 'backend/src/modules/ai-agent-skills/**'
- 'backend/src/modules/ai-review-queue/**'
- 'backend/src/modules/ai-copilot/**'
- 'backend/src/modules/lead-scoring-ai/**'
- 'backend/src/shared/state-machines/machines/ai-*.ts'
- 'backend/src/shared/state-machines/machines/training-*.ts'
prisma:
- 'backend/prisma/**'
e2e:
- 'e2e/**'
outputs:
ai-modules: ${{ steps.filter.outputs.ai-modules }}
backend: ${{ steps.filter.outputs.backend }}
e2e: ${{ steps.filter.outputs.e2e }}
frontend: ${{ steps.filter.outputs.frontend }}
prisma: ${{ steps.filter.outputs.prisma }}
shared: ${{ steps.filter.outputs.shared }}
...
|
detect-changes
|
null
|
["ubuntu-latest"]
|
21592
|
2
|
1777431267
|
1777432303
|
1777430952
|
1777432303
|
|
0
|
|
0
|
Edit
Delete
|
|
25238
|
18587
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
安装依赖
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
setup:
name: 安装依赖
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 缓存依赖
uses: actions/cache/save@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
...
|
setup
|
null
|
["ubuntu-latest"]
|
21593
|
2
|
1777432303
|
1777432329
|
1777430952
|
1777432330
|
|
0
|
|
0
|
Edit
Delete
|
|
25240
|
18587
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
前端静态检查
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
frontend-lint:
name: 前端静态检查
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.frontend == 'true'
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
- name: ESLint 检查
run: pnpm --filter juhi-frontend run lint
- name: 数组守卫检查
run: pnpm --filter juhi-frontend run check:array-guard
- name: TypeScript 类型检查
run: pnpm --filter juhi-frontend run type-check
...
|
frontend-lint
|
["setup","detect-changes"]
|
["ubuntu-latest"]
|
21604
|
2
|
1777432361
|
1777440671
|
1777430952
|
1777440671
|
|
1
|
|
0
|
Edit
Delete
|
|
25258
|
18587
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
覆盖率报告合并
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
coverage-report:
name: 覆盖率报告合并
runs-on: ubuntu-latest
if: always() && !cancelled()
steps:
- uses: actions/checkout@v4
- name: 下载所有覆盖率报告
uses: actions/download-artifact@v4
with:
merge-multiple: "true"
path: coverage-reports
pattern: '*-coverage'
- name: 上传到 Codecov
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: "false"
files: coverage-reports/**/*.info
verbose: "true"
...
|
coverage-report
|
["backend-unit-test","frontend-unit-te ["backend-unit-test","frontend-unit-test","shared-check"]...
|
["ubuntu-latest"]
|
21629
|
2
|
1777440675
|
1777440699
|
1777430952
|
1777440700
|
|
1
|
|
0
|
Edit
Delete
|
|
25261
|
18589
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
📥 收集测试结果
|
1
|
name: Test Report
"on":
workflow_run:
name: Test Report
"on":
workflow_run:
workflows:
- 'Test Suite'
- 'E2E Tests'
- 'Performance Tests'
types:
- completed
env:
NODE_VERSION: "18"
jobs:
collect-results:
name: "\U0001F4E5 收集测试结果"
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion != 'cancelled'
steps:
- name: "\U0001F4DD 记录工作流信息"
run: |
echo "工作流: ${{ github.event.workflow_run.name }}"
echo "结果: ${{ github.event.workflow_run.conclusion }}"
echo "运行 ID: ${{ github.event.workflow_run.id }}"
echo "分支: ${{ github.event.workflow_run.head_branch }}"
- name: "\U0001F4E5 下载测试结果 artifacts"
uses: actions/github-script@v7
with:
script: |
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
console.log('找到的 artifacts:');
for (const artifact of artifacts.data.artifacts) {
console.log(`- ${artifact.name} (${artifact.size_in_bytes} bytes)`);
}
// 保存 artifact 列表
const fs = require('fs');
fs.writeFileSync('artifacts.json', JSON.stringify(artifacts.data.artifacts, null, 2));
- name: "\U0001F4E4 上传 artifact 清单"
uses: actions/upload-artifact@v4
with:
name: artifact-list-${{ github.event.workflow_run.id }}
path: artifacts.json
retention-days: "7"
outputs:
run_id: ${{ github.event.workflow_run.id }}
workflow_conclusion: ${{ github.event.workflow_run.conclusion }}
workflow_name: ${{ github.event.workflow_run.name }}
...
|
collect-results
|
null
|
["ubuntu-latest"]
|
21596
|
2
|
1777432335
|
1777432339
|
1777431266
|
1777432339
|
|
0
|
|
0
|
Edit
Delete
|
|
25279
|
18595
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
📥 收集测试结果
|
1
|
name: Test Report
"on":
workflow_run:
name: Test Report
"on":
workflow_run:
workflows:
- 'Test Suite'
- 'E2E Tests'
- 'Performance Tests'
types:
- completed
env:
NODE_VERSION: "18"
jobs:
collect-results:
name: "\U0001F4E5 收集测试结果"
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion != 'cancelled'
steps:
- name: "\U0001F4DD 记录工作流信息"
run: |
echo "工作流: ${{ github.event.workflow_run.name }}"
echo "结果: ${{ github.event.workflow_run.conclusion }}"
echo "运行 ID: ${{ github.event.workflow_run.id }}"
echo "分支: ${{ github.event.workflow_run.head_branch }}"
- name: "\U0001F4E5 下载测试结果 artifacts"
uses: actions/github-script@v7
with:
script: |
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
console.log('找到的 artifacts:');
for (const artifact of artifacts.data.artifacts) {
console.log(`- ${artifact.name} (${artifact.size_in_bytes} bytes)`);
}
// 保存 artifact 列表
const fs = require('fs');
fs.writeFileSync('artifacts.json', JSON.stringify(artifacts.data.artifacts, null, 2));
- name: "\U0001F4E4 上传 artifact 清单"
uses: actions/upload-artifact@v4
with:
name: artifact-list-${{ github.event.workflow_run.id }}
path: artifacts.json
retention-days: "7"
outputs:
run_id: ${{ github.event.workflow_run.id }}
workflow_conclusion: ${{ github.event.workflow_run.conclusion }}
workflow_name: ${{ github.event.workflow_run.name }}
...
|
collect-results
|
null
|
["ubuntu-latest"]
|
21609
|
2
|
1777432369
|
1777432372
|
1777432344
|
1777432372
|
|
0
|
|
0
|
Edit
Delete
|
|
25284
|
18597
|
6
|
5
|
ec0c3a40069e8b31e369ceb9a13c7fd062040179
|
0
|
migration-safety
|
1
|
name: Database Migration Safety Check
"on" name: Database Migration Safety Check
"on":
push:
paths:
- 'backend/prisma/migrations/**'
- 'backend/prisma/schema.prisma'
- 'backend/prisma/schema/**'
pull_request:
paths:
- 'backend/prisma/migrations/**'
- 'backend/prisma/schema.prisma'
- 'backend/prisma/schema/**'
jobs:
migration-safety:
name: migration-safety
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: "20"
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: "8"
- name: Install dependencies
run: pnpm install --frozen-lockfile
working-directory: ./backend
- name: Verify Prisma schema mirror
run: pnpm run audit:prisma-schema-source
working-directory: ./backend
- name: Create PostgreSQL extensions on deploy DB
run: |
# 主部署库
psql -h localhost -U juhi -d juhi_revops_test -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"
psql -h localhost -U juhi -d juhi_revops_test -c "CREATE EXTENSION IF NOT EXISTS pgcrypto;"
psql -h localhost -U juhi -d juhi_revops_test -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"
psql -h localhost -U juhi -d juhi_revops_test -c "CREATE EXTENSION IF NOT EXISTS vector;"
env:
PGPASSWORD: test_password
- name: Create shadow DB for prisma migrate diff
run: |
# prisma migrate diff 在 ephemeral shadow DB 上 replay 历史 migrations,
# 然后与 prisma/schema 文件夹真源对比生成 drift SQL。必须是独立空库,不能用 deploy DB
psql -h localhost -U juhi -d postgres -c "CREATE DATABASE juhi_shadow_test;"
psql -h localhost -U juhi -d juhi_shadow_test -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"
psql -h localhost -U juhi -d juhi_shadow_test -c "CREATE EXTENSION IF NOT EXISTS pgcrypto;"
psql -h localhost -U juhi -d juhi_shadow_test -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"
psql -h localhost -U juhi -d juhi_shadow_test -c "CREATE EXTENSION IF NOT EXISTS vector;"
env:
PGPASSWORD: test_password
- name: Run migration safety checks
run: |
# Run the comprehensive migration safety check
./scripts/ci-migration-check.sh
env:
DATABASE_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
DIRECT_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
- name: Validate Prisma schema
run: |
npx prisma validate
working-directory: ./backend
env:
DATABASE_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
- name: Generate Prisma Client
run: |
npx prisma generate
working-directory: ./backend
env:
DATABASE_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
- name: Migration deploy gate (HARD)
run: |
./scripts/ci-migration-deploy-gate.sh
env:
DATABASE_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
DIRECT_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
SHADOW_DATABASE_URL: postgresql://juhi:test_password@localhost:5432/juhi_shadow_test
- if: always()
name: Upload migration drift artifacts
uses: actions/upload-artifact@v4
with:
if-no-files-found: warn
name: migration-drift-reports
path: |
reports/migration-drift-diff.latest.sql
reports/migration-drift-summary.latest.json
retention-days: "14"
services:
postgres:
image: pgvector/pgvector:pg16
env:
POSTGRES_DB: juhi_revops_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: juhi
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
...
|
migration-safety
|
null
|
["ubuntu-latest"]
|
21628
|
2
|
1777432567
|
1777440656
|
1777432567
|
1777440656
|
|
0
|
|
0
|
Edit
Delete
|
|
25519
|
18822
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
full-test-suite (chromium)
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
full-test-suite:
name: full-test-suite (chromium)
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'all')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build backend
run: |
cd backend
npm run build
- name: Build frontend
run: |
cd frontend
npm run build
- name: Install Playwright Browsers
run: npx playwright install --with-deps ${{ matrix.browser }}
- name: Start backend server
run: |
cd backend
npm run start &
sleep 10
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
- name: Start frontend server
run: |
cd frontend
npm run preview &
sleep 5
env:
VITE_API_URL: http://localhost:3000
- name: Run all E2E tests
run: |
cd e2e
npx playwright test --project=${{ matrix.browser }} --reporter=html,json
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload test results
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.browser }}
path: e2e/playwright-report/
retention-days: "30"
- if: always()
name: Upload test artifacts
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.browser }}
path: e2e/test-results/
retention-days: "30"
timeout-minutes: "60"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
browser:
- chromium
...
|
full-test-suite
|
null
|
["ubuntu-latest"]
|
21865
|
2
|
1777507260
|
1777507290
|
1777507256
|
1777507290
|
|
0
|
|
0
|
Edit
Delete
|
|
25520
|
18822
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
full-test-suite (firefox)
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
full-test-suite:
name: full-test-suite (firefox)
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'all')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build backend
run: |
cd backend
npm run build
- name: Build frontend
run: |
cd frontend
npm run build
- name: Install Playwright Browsers
run: npx playwright install --with-deps ${{ matrix.browser }}
- name: Start backend server
run: |
cd backend
npm run start &
sleep 10
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
- name: Start frontend server
run: |
cd frontend
npm run preview &
sleep 5
env:
VITE_API_URL: http://localhost:3000
- name: Run all E2E tests
run: |
cd e2e
npx playwright test --project=${{ matrix.browser }} --reporter=html,json
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload test results
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.browser }}
path: e2e/playwright-report/
retention-days: "30"
- if: always()
name: Upload test artifacts
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.browser }}
path: e2e/test-results/
retention-days: "30"
timeout-minutes: "60"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
browser:
- firefox
...
|
full-test-suite
|
null
|
["ubuntu-latest"]
|
21866
|
2
|
1777507290
|
1777507308
|
1777507256
|
1777507309
|
|
0
|
|
0
|
Edit
Delete
|
|
25521
|
18822
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
full-test-suite (webkit)
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
full-test-suite:
name: full-test-suite (webkit)
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'all')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build backend
run: |
cd backend
npm run build
- name: Build frontend
run: |
cd frontend
npm run build
- name: Install Playwright Browsers
run: npx playwright install --with-deps ${{ matrix.browser }}
- name: Start backend server
run: |
cd backend
npm run start &
sleep 10
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
- name: Start frontend server
run: |
cd frontend
npm run preview &
sleep 5
env:
VITE_API_URL: http://localhost:3000
- name: Run all E2E tests
run: |
cd e2e
npx playwright test --project=${{ matrix.browser }} --reporter=html,json
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload test results
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.browser }}
path: e2e/playwright-report/
retention-days: "30"
- if: always()
name: Upload test artifacts
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.browser }}
path: e2e/test-results/
retention-days: "30"
timeout-minutes: "60"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: "false"
matrix:
browser:
- webkit
...
|
full-test-suite
|
null
|
["ubuntu-latest"]
|
21867
|
2
|
1777507309
|
1777507326
|
1777507256
|
1777507327
|
|
0
|
|
0
|
Edit
Delete
|
|
25523
|
18822
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
performance-benchmarks
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
performance-benchmarks:
name: performance-benchmarks
runs-on: ubuntu-latest
if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.test_suite == 'performance')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build and start services
run: |
cd backend && npm run build && npm run start &
cd frontend && npm run build && npm run preview &
sleep 15
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: production
VITE_API_URL: http://localhost:3000
- name: Install Playwright
run: npx playwright install --with-deps chromium
- name: Run performance tests
run: |
cd e2e
npx playwright test \
tests/flows/complete-sales-flow.spec.ts \
tests/lead-to-cash.spec.ts \
--reporter=html,json
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- name: Generate performance report
run: |
cd e2e
node scripts/generate-performance-report.js
- if: always()
name: Upload performance results
uses: actions/upload-artifact@v4
with:
name: performance-report
path: |
e2e/playwright-report/
e2e/performance-results.json
retention-days: "90"
- if: github.event_name == 'schedule'
name: Comment with performance results
uses: actions/github-script@v7
with:
script: "const fs = require('fs');\nconst results = JSON.parse(fs.readFileSync('e2e/performance-results.json', 'utf8'));\n\nconst comment = `\n## \U0001F4CA 每日性能基准测试报告\n\n- **页面加载时间**: ${results.pageLoadTime}ms\n- **首次内容绘制 (FCP)**: ${results.fcp}ms\n- **最大内容绘制 (LCP)**: ${results.lcp}ms\n- **首次输入延迟 (FID)**: ${results.fid}ms\n- **累积布局偏移 (CLS)**: ${results.cls}\n\n${results.passed ? '✅ 所有性能指标达标' : '⚠️ 部分指标未达标,请关注'}\n`;\n\n// 创建 Issue 或发送通知\n// ...\n"
timeout-minutes: "30"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
...
|
performance-benchmarks
|
null
|
["ubuntu-latest"]
|
21869
|
2
|
1777507329
|
1777507347
|
1777507256
|
1777507348
|
|
0
|
|
0
|
Edit
Delete
|
|
25525
|
18822
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
test-summary
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
test-summary:
name: test-summary
runs-on: ubuntu-latest
if: always()
steps:
- name: Download all test artifacts
uses: actions/download-artifact@v4
- name: Generate summary report
run: "echo \"## \U0001F9EA E2E 测试汇总\" >> $GITHUB_STEP_SUMMARY\necho \"\" >> $GITHUB_STEP_SUMMARY\n\nif [ -d \"playwright-report-pr\" ]; then\n echo \"### PR 快速验证\" >> $GITHUB_STEP_SUMMARY\n echo \"✅ 关键测试通过\" >> $GITHUB_STEP_SUMMARY\nfi\n\nif [ -d \"business-flows-report\" ]; then\n echo \"### 业务流程测试\" >> $GITHUB_STEP_SUMMARY\n echo \"✅ 业务流程测试完成\" >> $GITHUB_STEP_SUMMARY\nfi\n\nif [ -d \"performance-report\" ]; then\n echo \"### 性能基准测试\" >> $GITHUB_STEP_SUMMARY\n echo \"\U0001F4CA 性能测试报告已生成\" >> $GITHUB_STEP_SUMMARY\nfi\n\nif [ -d \"visual-regression-report\" ]; then\n echo \"### 视觉回归测试\" >> $GITHUB_STEP_SUMMARY\n echo \"\U0001F3A8 视觉对比完成\" >> $GITHUB_STEP_SUMMARY\nfi\n"
...
|
test-summary
|
["pr-validation","full-test-suite" ["pr-validation","full-test-suite","business-flows","performance-benchmarks","visual-regression"]...
|
["ubuntu-latest"]
|
21871
|
2
|
1777507350
|
1777507353
|
1777507256
|
1777507353
|
|
1
|
|
0
|
Edit
Delete
|
|
25554
|
18851
|
6
|
5
|
982b47544d9cefb513875cc84c6c36bf1ee27fb2
|
0
|
Frontend Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
frontend-typecheck:
name: Frontend Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Build shared package
run: pnpm -C shared run build
- name: 前端类型检查(vue-tsc --noEmit)
run: pnpm --filter ./frontend run type-check
permissions:
contents: read
...
|
frontend-typecheck
|
null
|
["ubuntu-latest"]
|
21900
|
2
|
1777515699
|
1777515790
|
1777515698
|
1777515790
|
|
0
|
|
0
|
Edit
Delete
|
|
25555
|
18851
|
6
|
5
|
982b47544d9cefb513875cc84c6c36bf1ee27fb2
|
0
|
Lint & Type Check
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Backend type check
run: pnpm -C backend run type-check
- name: Lint
run: pnpm -C backend run lint
permissions:
contents: read
...
|
lint-and-typecheck
|
null
|
["ubuntu-latest"]
|
21901
|
2
|
1777515790
|
1777515881
|
1777515698
|
1777515881
|
|
0
|
|
0
|
Edit
Delete
|
|
25560
|
18852
|
6
|
5
|
982b47544d9cefb513875cc84c6c36bf1ee27fb2
|
0
|
pr-validation
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
pr-validation:
name: pr-validation
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
- name: Build backend
run: |
cd backend
npm run build
- name: Build frontend
run: |
cd frontend
npm run build
- name: Install Playwright Browsers
run: npx playwright install --with-deps chromium
- name: Start backend server
run: |
cd backend
npm run start &
sleep 10
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
NODE_ENV: test
- name: Start frontend server
run: |
cd frontend
npm run preview &
sleep 5
env:
VITE_API_URL: http://localhost:3000
- name: Run critical E2E tests
run: |
cd e2e
npx playwright test \
tests/auth/login.spec.ts \
tests/navigation/full-menu-click.spec.ts \
tests/multi-tenant/data-isolation.spec.ts \
tests/form-interactions/ \
--reporter=html
env:
E2E_BASE_URL: http://localhost:5173
E2E_TEST_USER: admin@juhi.com
E2E_TEST_PASSWORD: Admin@123
- if: always()
name: Upload test results
uses: actions/upload-artifact@v4
with:
name: playwright-report-pr
path: e2e/playwright-report/
retention-days: "7"
- if: always() && github.event_name == 'pull_request'
name: Comment PR with test results
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const reportPath = 'e2e/playwright-report/index.html';
const testsPassed = !fs.existsSync('e2e/test-results/');
const comment = testsPassed
? '✅ E2E 测试通过!'
: '❌ E2E 测试失败,请查看报告';
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
timeout-minutes: "30"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: test_user
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
...
|
pr-validation
|
null
|
["ubuntu-latest"]
|
21902
|
2
|
1777515882
|
1777515945
|
1777515698
|
1777515945
|
|
0
|
|
0
|
Edit
Delete
|
|
25567
|
18852
|
6
|
5
|
982b47544d9cefb513875cc84c6c36bf1ee27fb2
|
0
|
test-summary
|
1
|
name: E2E Tests
"on":
# PR validation name: E2E Tests
"on":
# PR validation - 运行关键测试
pull_request:
branches: [main, develop]
paths:
- 'frontend/**'
- 'backend/**'
- 'e2e/**'
- 'package.json'
- 'pnpm-lock.yaml'
# Push to main - 运行完整测试套件
push:
branches: [main]
# 每日定时全量测试 (UTC 时间 00:00 = 北京时间 08:00)
schedule:
- cron: '0 0 * * *'
# 手动触发
workflow_dispatch:
inputs:
test_suite:
description: 'Test suite to run'
required: true
default: 'all'
type: choice
options:
- all
- critical
- business-flows
- visual-regression
- performance
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
test-summary:
name: test-summary
runs-on: ubuntu-latest
if: always()
steps:
- name: Download all test artifacts
uses: actions/download-artifact@v4
- name: Generate summary report
run: "echo \"## \U0001F9EA E2E 测试汇总\" >> $GITHUB_STEP_SUMMARY\necho \"\" >> $GITHUB_STEP_SUMMARY\n\nif [ -d \"playwright-report-pr\" ]; then\n echo \"### PR 快速验证\" >> $GITHUB_STEP_SUMMARY\n echo \"✅ 关键测试通过\" >> $GITHUB_STEP_SUMMARY\nfi\n\nif [ -d \"business-flows-report\" ]; then\n echo \"### 业务流程测试\" >> $GITHUB_STEP_SUMMARY\n echo \"✅ 业务流程测试完成\" >> $GITHUB_STEP_SUMMARY\nfi\n\nif [ -d \"performance-report\" ]; then\n echo \"### 性能基准测试\" >> $GITHUB_STEP_SUMMARY\n echo \"\U0001F4CA 性能测试报告已生成\" >> $GITHUB_STEP_SUMMARY\nfi\n\nif [ -d \"visual-regression-report\" ]; then\n echo \"### 视觉回归测试\" >> $GITHUB_STEP_SUMMARY\n echo \"\U0001F3A8 视觉对比完成\" >> $GITHUB_STEP_SUMMARY\nfi\n"
...
|
test-summary
|
["pr-validation","full-test-suite" ["pr-validation","full-test-suite","business-flows","performance-benchmarks","visual-regression"]...
|
["ubuntu-latest"]
|
21919
|
2
|
1777516182
|
1777516272
|
1777515698
|
1777516273
|
|
1
|
|
0
|
Edit
Delete
|
|
25568
|
18853
|
6
|
5
|
982b47544d9cefb513875cc84c6c36bf1ee27fb2
|
0
|
migration-safety
|
1
|
name: Database Migration Safety Check
"on" name: Database Migration Safety Check
"on":
push:
paths:
- 'backend/prisma/migrations/**'
- 'backend/prisma/schema.prisma'
- 'backend/prisma/schema/**'
pull_request:
paths:
- 'backend/prisma/migrations/**'
- 'backend/prisma/schema.prisma'
- 'backend/prisma/schema/**'
jobs:
migration-safety:
name: migration-safety
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: "20"
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: "8"
- name: Install dependencies
run: pnpm install --frozen-lockfile
working-directory: ./backend
- name: Verify Prisma schema mirror
run: pnpm run audit:prisma-schema-source
working-directory: ./backend
- name: Create PostgreSQL extensions on deploy DB
run: |
# 主部署库
psql -h localhost -U juhi -d juhi_revops_test -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"
psql -h localhost -U juhi -d juhi_revops_test -c "CREATE EXTENSION IF NOT EXISTS pgcrypto;"
psql -h localhost -U juhi -d juhi_revops_test -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"
psql -h localhost -U juhi -d juhi_revops_test -c "CREATE EXTENSION IF NOT EXISTS vector;"
env:
PGPASSWORD: test_password
- name: Create shadow DB for prisma migrate diff
run: |
# prisma migrate diff 在 ephemeral shadow DB 上 replay 历史 migrations,
# 然后与 prisma/schema 文件夹真源对比生成 drift SQL。必须是独立空库,不能用 deploy DB
psql -h localhost -U juhi -d postgres -c "CREATE DATABASE juhi_shadow_test;"
psql -h localhost -U juhi -d juhi_shadow_test -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"
psql -h localhost -U juhi -d juhi_shadow_test -c "CREATE EXTENSION IF NOT EXISTS pgcrypto;"
psql -h localhost -U juhi -d juhi_shadow_test -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"
psql -h localhost -U juhi -d juhi_shadow_test -c "CREATE EXTENSION IF NOT EXISTS vector;"
env:
PGPASSWORD: test_password
- name: Run migration safety checks
run: |
# Run the comprehensive migration safety check
./scripts/ci-migration-check.sh
env:
DATABASE_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
DIRECT_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
- name: Validate Prisma schema
run: |
npx prisma validate
working-directory: ./backend
env:
DATABASE_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
- name: Generate Prisma Client
run: |
npx prisma generate
working-directory: ./backend
env:
DATABASE_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
- name: Migration deploy gate (HARD)
run: |
./scripts/ci-migration-deploy-gate.sh
env:
DATABASE_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
DIRECT_URL: postgresql://juhi:test_password@localhost:5432/juhi_revops_test
SHADOW_DATABASE_URL: postgresql://juhi:test_password@localhost:5432/juhi_shadow_test
- if: always()
name: Upload migration drift artifacts
uses: actions/upload-artifact@v4
with:
if-no-files-found: warn
name: migration-drift-reports
path: |
reports/migration-drift-diff.latest.sql
reports/migration-drift-summary.latest.json
retention-days: "14"
services:
postgres:
image: pgvector/pgvector:pg16
env:
POSTGRES_DB: juhi_revops_test
POSTGRES_PASSWORD: test_password
POSTGRES_USER: juhi
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
...
|
migration-safety
|
null
|
["ubuntu-latest"]
|
21909
|
2
|
1777515957
|
1777515988
|
1777515699
|
1777515988
|
|
0
|
|
0
|
Edit
Delete
|
|
25570
|
18854
|
6
|
5
|
982b47544d9cefb513875cc84c6c36bf1ee27fb2
|
0
|
📊 API 基准测试
|
1
|
name: Performance Tests
"on":
# 每周一凌晨 name: Performance Tests
"on":
# 每周一凌晨 2 点运行
schedule:
- cron: '0 2 * * 1'
# 允许手动触发
workflow_dispatch:
inputs:
test_type:
description: '测试类型'
required: true
default: 'benchmark'
type: choice
options:
- benchmark
- load
- stress
- all
duration:
description: '测试持续时间(秒)'
required: false
default: '60'
type: string
concurrency:
description: '并发数'
required: false
default: '10'
type: string
# PR 触发时只运行基准测试
pull_request:
branches: [main]
paths:
- 'backend/src/**'
- 'backend/prisma/**'
env:
NODE_VERSION: "20"
PNPM_VERSION: "9"
jobs:
benchmark:
name: "\U0001F4CA API 基准测试"
runs-on: ubuntu-latest
if: needs.setup.outputs.test_type == 'benchmark' || needs.setup.outputs.test_type == 'all'
steps:
- name: "\U0001F4E5 检出代码"
uses: actions/checkout@v4
- name: "\U0001F4E6 安装 pnpm"
uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- name: "\U0001F7E2 设置 Node.js"
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: "\U0001F4E6 安装依赖"
run: pnpm install --frozen-lockfile
- name: "\U0001F5C4️ 初始化数据库"
run: |
cd backend
npx prisma migrate deploy
npx prisma db seed
env:
DATABASE_URL: postgresql://test:test@localhost:5432/juhi_perf
- name: "\U0001F528 构建后端"
run: |
pnpm --filter shared build
pnpm --filter backend build
- name: "\U0001F680 启动后端服务"
run: |
cd backend
npm run start &
sleep 10
env:
NODE_ENV: production
PORT: 3000
DATABASE_URL: postgresql://test:test@localhost:5432/juhi_perf
REDIS_URL: redis://localhost:6379
JWT_SECRET: perf-test-jwt-secret
REFRESH_TOKEN_SECRET: perf-test-refresh-token
- name: ⏳ 等待服务就绪
run: |
timeout 60 bash -c 'until curl -s http://localhost:3000/health > /dev/null; do sleep 2; done'
echo "服务已就绪"
- name: "\U0001F4CA 运行基准测试"
run: |
cd backend
npm run test -- tests/examples/performance.test.ts --reporter=json --outputFile=benchmark-results.json
env:
DATABASE_URL: postgresql://test:test@localhost:5432/juhi_perf
API_URL: http://localhost:3000
- name: "\U0001F4DD 生成基准报告"
run: "echo \"## \U0001F4CA API 基准测试报告\" >> $GITHUB_STEP_SUMMARY\necho \"\" >> $GITHUB_STEP_SUMMARY\necho \"测试时间: $(date)\" >> $GITHUB_STEP_SUMMARY\necho \"\" >> $GITHUB_STEP_SUMMARY\n\nif [ -f \"backend/benchmark-results.json\" ]; then\n echo \"### 测试结果\" >> $GITHUB_STEP_SUMMARY\n cat backend/benchmark-results.json | jq '.testResults[].assertionResults[] | {name: .ancestorTitles[-1] + \" > \" + .title, status: .status}' >> $GITHUB_STEP_SUMMARY || true\nfi\n"
- name: "\U0001F4E4 上传基准测试结果"
uses: actions/upload-artifact@v4
with:
name: benchmark-results
path: backend/benchmark-results.json
retention-days: "30"
timeout-minutes: "30"
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: juhi_perf
POSTGRES_PASSWORD: test
POSTGRES_USER: test
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
...
|
benchmark
|
["setup"]
|
["ubuntu-latest"]
|
21921
|
2
|
1777516692
|
1777522238
|
1777515700
|
1777522238
|
|
1
|
|
0
|
Edit
Delete
|
|
25576
|
18855
|
6
|
5
|
982b47544d9cefb513875cc84c6c36bf1ee27fb2
|
0
|
检测代码变更
|
1
|
name: PR Validation
"on":
pull_request name: PR Validation
"on":
pull_request:
branches: [main, develop]
types: [opened, synchronize, reopened]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
detect-changes:
name: 检测代码变更
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: filter
uses: dorny/paths-filter@v3
with:
filters: |
backend:
- 'backend/**'
- 'shared/**'
frontend:
- 'frontend/**'
- 'shared/**'
shared:
- 'shared/**'
outputs:
backend: ${{ steps.filter.outputs.backend }}
frontend: ${{ steps.filter.outputs.frontend }}
shared: ${{ steps.filter.outputs.shared }}
...
|
detect-changes
|
null
|
["ubuntu-latest"]
|
21911
|
2
|
1777515992
|
1777516022
|
1777515701
|
1777516023
|
|
0
|
|
0
|
Edit
Delete
|
|
25577
|
18855
|
6
|
5
|
982b47544d9cefb513875cc84c6c36bf1ee27fb2
|
0
|
安装依赖
|
1
|
name: PR Validation
"on":
pull_request name: PR Validation
"on":
pull_request:
branches: [main, develop]
types: [opened, synchronize, reopened]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
setup:
name: 安装依赖
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 缓存 node_modules
uses: actions/cache/save@v4
with:
key: pr-deps-${{ runner.os }}-${{ github.event.pull_request.number }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
...
|
setup
|
null
|
["ubuntu-latest"]
|
21912
|
2
|
1777516023
|
1777516053
|
1777515701
|
1777516054
|
|
0
|
|
0
|
Edit
Delete
|
|
25581
|
18855
|
6
|
5
|
982b47544d9cefb513875cc84c6c36bf1ee27fb2
|
0
|
提交信息验证
|
1
|
name: PR Validation
"on":
pull_request name: PR Validation
"on":
pull_request:
branches: [main, develop]
types: [opened, synchronize, reopened]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
commit-validation:
name: 提交信息验证
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: 验证提交信息格式
run: |
# 获取 PR 中的所有提交
COMMITS=$(git log --format="%s" origin/${{ github.base_ref }}..HEAD)
echo "检查提交信息格式..."
WARNINGS=0
while IFS= read -r commit; do
# 检查是否符合 Conventional Commits 格式
if ! echo "$commit" | grep -qE "^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)(\(.+\))?: .+"; then
echo "⚠️ 提交信息格式不符合规范: $commit"
echo " 建议格式: type(scope): description"
echo " 类型: feat, fix, docs, style, refactor, perf, test, chore, ci, build, revert"
WARNINGS=$((WARNINGS + 1))
fi
done <<< "$COMMITS"
if [ $WARNINGS -gt 0 ]; then
echo ""
echo "⚠️ 共有 $WARNINGS 个提交信息不符合规范(非阻塞性警告)"
else
echo "✅ 所有提交信息格式正确"
fi
...
|
commit-validation
|
null
|
["ubuntu-latest"]
|
21913
|
2
|
1777516054
|
1777516084
|
1777515701
|
1777516084
|
|
0
|
|
0
|
Edit
Delete
|
|
25582
|
18855
|
6
|
5
|
982b47544d9cefb513875cc84c6c36bf1ee27fb2
|
0
|
PR 描述验证
|
1
|
name: PR Validation
"on":
pull_request name: PR Validation
"on":
pull_request:
branches: [main, develop]
types: [opened, synchronize, reopened]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
pr-description:
name: PR 描述验证
runs-on: ubuntu-latest
steps:
- name: 检查 PR 描述
uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request;
const body = pr.body || '';
let warnings = [];
if (body.length < 50) {
warnings.push('PR 描述过短,建议添加更详细的说明');
}
// 检查是否包含关键部分
const hasChanges = body.includes('变更') || body.includes('Changes') || body.includes('##');
if (!hasChanges) {
warnings.push('建议在 PR 描述中说明主要变更内容');
}
if (warnings.length > 0) {
core.warning('PR 描述建议:\n' + warnings.join('\n'));
} else {
console.log('✅ PR 描述符合规范');
}
...
|
pr-description
|
null
|
["ubuntu-latest"]
|
21914
|
2
|
1777516085
|
1777516115
|
1777515701
|
1777516115
|
|
0
|
|
0
|
Edit
Delete
|
|
25584
|
18856
|
6
|
5
|
982b47544d9cefb513875cc84c6c36bf1ee27fb2
|
0
|
检测代码变更
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
detect-changes:
name: 检测代码变更
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: filter
uses: dorny/paths-filter@v3
with:
filters: |
backend:
- 'backend/**'
- 'shared/**'
frontend:
- 'frontend/**'
- 'shared/**'
shared:
- 'shared/**'
ai-modules:
- 'backend/src/modules/ai-agents/**'
- 'backend/src/modules/ai-agent-skills/**'
- 'backend/src/modules/ai-review-queue/**'
- 'backend/src/modules/ai-copilot/**'
- 'backend/src/modules/lead-scoring-ai/**'
- 'backend/src/shared/state-machines/machines/ai-*.ts'
- 'backend/src/shared/state-machines/machines/training-*.ts'
prisma:
- 'backend/prisma/**'
e2e:
- 'e2e/**'
outputs:
ai-modules: ${{ steps.filter.outputs.ai-modules }}
backend: ${{ steps.filter.outputs.backend }}
e2e: ${{ steps.filter.outputs.e2e }}
frontend: ${{ steps.filter.outputs.frontend }}
prisma: ${{ steps.filter.outputs.prisma }}
shared: ${{ steps.filter.outputs.shared }}
...
|
detect-changes
|
null
|
["ubuntu-latest"]
|
21915
|
2
|
1777516115
|
1777516146
|
1777515702
|
1777516146
|
|
0
|
|
0
|
Edit
Delete
|
|
25585
|
18856
|
6
|
5
|
982b47544d9cefb513875cc84c6c36bf1ee27fb2
|
0
|
安装依赖
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
setup:
name: 安装依赖
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 缓存依赖
uses: actions/cache/save@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
...
|
setup
|
null
|
["ubuntu-latest"]
|
21916
|
2
|
1777516146
|
1777516177
|
1777515702
|
1777516177
|
|
0
|
|
0
|
Edit
Delete
|
|
25605
|
18856
|
6
|
5
|
982b47544d9cefb513875cc84c6c36bf1ee27fb2
|
0
|
覆盖率报告合并
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
coverage-report:
name: 覆盖率报告合并
runs-on: ubuntu-latest
if: always() && !cancelled()
steps:
- uses: actions/checkout@v4
- name: 下载所有覆盖率报告
uses: actions/download-artifact@v4
with:
merge-multiple: "true"
path: coverage-reports
pattern: '*-coverage'
- name: 上传到 Codecov
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: "false"
files: coverage-reports/**/*.info
verbose: "true"
...
|
coverage-report
|
["backend-unit-test","frontend-unit-te ["backend-unit-test","frontend-unit-test","shared-check"]...
|
["ubuntu-latest"]
|
21947
|
2
|
1777522388
|
1777522408
|
1777515702
|
1777522409
|
|
1
|
|
0
|
Edit
Delete
|
|
25608
|
18858
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
📥 收集测试结果
|
1
|
name: Test Report
"on":
workflow_run:
name: Test Report
"on":
workflow_run:
workflows:
- 'Test Suite'
- 'E2E Tests'
- 'Performance Tests'
types:
- completed
env:
NODE_VERSION: "18"
jobs:
collect-results:
name: "\U0001F4E5 收集测试结果"
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion != 'cancelled'
steps:
- name: "\U0001F4DD 记录工作流信息"
run: |
echo "工作流: ${{ github.event.workflow_run.name }}"
echo "结果: ${{ github.event.workflow_run.conclusion }}"
echo "运行 ID: ${{ github.event.workflow_run.id }}"
echo "分支: ${{ github.event.workflow_run.head_branch }}"
- name: "\U0001F4E5 下载测试结果 artifacts"
uses: actions/github-script@v7
with:
script: |
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
console.log('找到的 artifacts:');
for (const artifact of artifacts.data.artifacts) {
console.log(`- ${artifact.name} (${artifact.size_in_bytes} bytes)`);
}
// 保存 artifact 列表
const fs = require('fs');
fs.writeFileSync('artifacts.json', JSON.stringify(artifacts.data.artifacts, null, 2));
- name: "\U0001F4E4 上传 artifact 清单"
uses: actions/upload-artifact@v4
with:
name: artifact-list-${{ github.event.workflow_run.id }}
path: artifacts.json
retention-days: "7"
outputs:
run_id: ${{ github.event.workflow_run.id }}
workflow_conclusion: ${{ github.event.workflow_run.conclusion }}
workflow_name: ${{ github.event.workflow_run.name }}
...
|
collect-results
|
null
|
["ubuntu-latest"]
|
21920
|
2
|
1777516274
|
1777516691
|
1777515957
|
1777516691
|
|
0
|
|
0
|
Edit
Delete
|
|
25613
|
18860
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
📥 收集测试结果
|
1
|
name: Test Report
"on":
workflow_run:
name: Test Report
"on":
workflow_run:
workflows:
- 'Test Suite'
- 'E2E Tests'
- 'Performance Tests'
types:
- completed
env:
NODE_VERSION: "18"
jobs:
collect-results:
name: "\U0001F4E5 收集测试结果"
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion != 'cancelled'
steps:
- name: "\U0001F4DD 记录工作流信息"
run: |
echo "工作流: ${{ github.event.workflow_run.name }}"
echo "结果: ${{ github.event.workflow_run.conclusion }}"
echo "运行 ID: ${{ github.event.workflow_run.id }}"
echo "分支: ${{ github.event.workflow_run.head_branch }}"
- name: "\U0001F4E5 下载测试结果 artifacts"
uses: actions/github-script@v7
with:
script: |
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
console.log('找到的 artifacts:');
for (const artifact of artifacts.data.artifacts) {
console.log(`- ${artifact.name} (${artifact.size_in_bytes} bytes)`);
}
// 保存 artifact 列表
const fs = require('fs');
fs.writeFileSync('artifacts.json', JSON.stringify(artifacts.data.artifacts, null, 2));
- name: "\U0001F4E4 上传 artifact 清单"
uses: actions/upload-artifact@v4
with:
name: artifact-list-${{ github.event.workflow_run.id }}
path: artifacts.json
retention-days: "7"
outputs:
run_id: ${{ github.event.workflow_run.id }}
workflow_conclusion: ${{ github.event.workflow_run.conclusion }}
workflow_name: ${{ github.event.workflow_run.name }}
...
|
collect-results
|
null
|
["ubuntu-latest"]
|
21934
|
2
|
1777522352
|
1777522357
|
1777516274
|
1777522358
|
|
0
|
|
0
|
Edit
Delete
|
|
25619
|
18863
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
📥 收集测试结果
|
1
|
name: Test Report
"on":
workflow_run:
name: Test Report
"on":
workflow_run:
workflows:
- 'Test Suite'
- 'E2E Tests'
- 'Performance Tests'
types:
- completed
env:
NODE_VERSION: "18"
jobs:
collect-results:
name: "\U0001F4E5 收集测试结果"
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion != 'cancelled'
steps:
- name: "\U0001F4DD 记录工作流信息"
run: |
echo "工作流: ${{ github.event.workflow_run.name }}"
echo "结果: ${{ github.event.workflow_run.conclusion }}"
echo "运行 ID: ${{ github.event.workflow_run.id }}"
echo "分支: ${{ github.event.workflow_run.head_branch }}"
- name: "\U0001F4E5 下载测试结果 artifacts"
uses: actions/github-script@v7
with:
script: |
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
console.log('找到的 artifacts:');
for (const artifact of artifacts.data.artifacts) {
console.log(`- ${artifact.name} (${artifact.size_in_bytes} bytes)`);
}
// 保存 artifact 列表
const fs = require('fs');
fs.writeFileSync('artifacts.json', JSON.stringify(artifacts.data.artifacts, null, 2));
- name: "\U0001F4E4 上传 artifact 清单"
uses: actions/upload-artifact@v4
with:
name: artifact-list-${{ github.event.workflow_run.id }}
path: artifacts.json
retention-days: "7"
outputs:
run_id: ${{ github.event.workflow_run.id }}
workflow_conclusion: ${{ github.event.workflow_run.conclusion }}
workflow_name: ${{ github.event.workflow_run.name }}
...
|
collect-results
|
null
|
["ubuntu-latest"]
|
21939
|
2
|
1777522367
|
1777522369
|
1777522331
|
1777522370
|
|
0
|
|
0
|
Edit
Delete
|
|
25623
|
18864
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
📥 收集测试结果
|
1
|
name: Test Report
"on":
workflow_run:
name: Test Report
"on":
workflow_run:
workflows:
- 'Test Suite'
- 'E2E Tests'
- 'Performance Tests'
types:
- completed
env:
NODE_VERSION: "18"
jobs:
collect-results:
name: "\U0001F4E5 收集测试结果"
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion != 'cancelled'
steps:
- name: "\U0001F4DD 记录工作流信息"
run: |
echo "工作流: ${{ github.event.workflow_run.name }}"
echo "结果: ${{ github.event.workflow_run.conclusion }}"
echo "运行 ID: ${{ github.event.workflow_run.id }}"
echo "分支: ${{ github.event.workflow_run.head_branch }}"
- name: "\U0001F4E5 下载测试结果 artifacts"
uses: actions/github-script@v7
with:
script: |
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
console.log('找到的 artifacts:');
for (const artifact of artifacts.data.artifacts) {
console.log(`- ${artifact.name} (${artifact.size_in_bytes} bytes)`);
}
// 保存 artifact 列表
const fs = require('fs');
fs.writeFileSync('artifacts.json', JSON.stringify(artifacts.data.artifacts, null, 2));
- name: "\U0001F4E4 上传 artifact 清单"
uses: actions/upload-artifact@v4
with:
name: artifact-list-${{ github.event.workflow_run.id }}
path: artifacts.json
retention-days: "7"
outputs:
run_id: ${{ github.event.workflow_run.id }}
workflow_conclusion: ${{ github.event.workflow_run.conclusion }}
workflow_name: ${{ github.event.workflow_run.name }}
...
|
collect-results
|
null
|
["ubuntu-latest"]
|
21952
|
2
|
1777522417
|
1777522420
|
1777522374
|
1777522420
|
|
0
|
|
0
|
Edit
Delete
|
|
25627
|
18865
|
6
|
5
|
468c7319f39e251cdf8eb96c3aa63f4db200a7db
|
0
|
📥 收集测试结果
|
1
|
name: Test Report
"on":
workflow_run:
name: Test Report
"on":
workflow_run:
workflows:
- 'Test Suite'
- 'E2E Tests'
- 'Performance Tests'
types:
- completed
env:
NODE_VERSION: "18"
jobs:
collect-results:
name: "\U0001F4E5 收集测试结果"
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion != 'cancelled'
steps:
- name: "\U0001F4DD 记录工作流信息"
run: |
echo "工作流: ${{ github.event.workflow_run.name }}"
echo "结果: ${{ github.event.workflow_run.conclusion }}"
echo "运行 ID: ${{ github.event.workflow_run.id }}"
echo "分支: ${{ github.event.workflow_run.head_branch }}"
- name: "\U0001F4E5 下载测试结果 artifacts"
uses: actions/github-script@v7
with:
script: |
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
console.log('找到的 artifacts:');
for (const artifact of artifacts.data.artifacts) {
console.log(`- ${artifact.name} (${artifact.size_in_bytes} bytes)`);
}
// 保存 artifact 列表
const fs = require('fs');
fs.writeFileSync('artifacts.json', JSON.stringify(artifacts.data.artifacts, null, 2));
- name: "\U0001F4E4 上传 artifact 清单"
uses: actions/upload-artifact@v4
with:
name: artifact-list-${{ github.event.workflow_run.id }}
path: artifacts.json
retention-days: "7"
outputs:
run_id: ${{ github.event.workflow_run.id }}
workflow_conclusion: ${{ github.event.workflow_run.conclusion }}
workflow_name: ${{ github.event.workflow_run.name }}
...
|
collect-results
|
null
|
["ubuntu-latest"]
|
21953
|
2
|
1777522420
|
1777522424
|
1777522375
|
1777522424
|
|
0
|
|
0
|
Edit
Delete
|