|
30745
|
23358
|
6
|
5
|
534799e0b1707368df37aff7b3df545a6ca1064a
|
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:
E2E_SKIP_WEB_SERVER: "true"
NODE_OPTIONS: --max-old-space-size=8192
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
continue-on-error: true
- 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"
permissions:
contents: read
pull-requests: write # github-script 评论 E2E 测试结果
checks: write
issues: write
...
|
test-summary
|
["pr-validation","full-test-suite" ["pr-validation","full-test-suite","business-flows","performance-benchmarks","visual-regression"]...
|
["ubuntu-latest"]
|
26915
|
2
|
1778895442
|
1778895532
|
1778889628
|
1778895533
|
|
1
|
|
0
|
Edit
Delete
|
|
30753
|
23363
|
6
|
5
|
2d843a1a119ca0eda1a552c12468ff3840669487
|
0
|
Frontend Type Check
|
1
|
name: Gitea CI
"on":
push:
bra name: Gitea CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_OPTIONS: --max-old-space-size=8192
jobs:
frontend-typecheck:
name: Frontend Type Check
runs-on: ubuntu-latest
steps:
- name: Checkout from Gitea(不依赖 github.com)
run: |
set -eu
git config --global --add safe.directory "$(pwd)"
git init -q .
git remote add origin \
"https://x-access-token:${{ github.token }}@${GITHUB_SERVER_URL#https://}/${GITHUB_REPOSITORY}.git"
git fetch --depth 1 origin "${GITHUB_REF}"
git checkout -q FETCH_HEAD
- name: Enable pnpm via corepack
run: |
corepack enable
corepack prepare pnpm@9 --activate
pnpm -v
- 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
container: node:20-bookworm
...
|
frontend-typecheck
|
null
|
["ubuntu-latest"]
|
26908
|
2
|
1778893294
|
1778893325
|
1778890649
|
1778893325
|
|
0
|
|
0
|
Edit
Delete
|
|
30754
|
23363
|
6
|
5
|
2d843a1a119ca0eda1a552c12468ff3840669487
|
0
|
Lint & Type Check
|
1
|
name: Gitea CI
"on":
push:
bra name: Gitea CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_OPTIONS: --max-old-space-size=8192
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- name: Checkout from Gitea(不依赖 github.com)
run: |
set -eu
git config --global --add safe.directory "$(pwd)"
git init -q .
git remote add origin \
"https://x-access-token:${{ github.token }}@${GITHUB_SERVER_URL#https://}/${GITHUB_REPOSITORY}.git"
git fetch --depth 1 origin "${GITHUB_REF}"
git checkout -q FETCH_HEAD
- name: Enable pnpm via corepack
run: |
corepack enable
corepack prepare pnpm@9 --activate
pnpm -v
- 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
container: node:20-bookworm
...
|
lint-and-typecheck
|
null
|
["ubuntu-latest"]
|
26909
|
2
|
1778893325
|
1778893356
|
1778890649
|
1778893356
|
|
0
|
|
0
|
Edit
Delete
|
|
30821
|
23381
|
13
|
5
|
6c80c00976d1c5ac4aaa5f76d10cf1e7b4f59448
|
0
|
Analyze (java)
|
1
|
name: CodeQL Analysis
"on":
push:
name: CodeQL Analysis
"on":
push:
branches: [develop, master, main]
pull_request:
branches: [develop, master, main]
schedule:
# 每周一凌晨3点运行
- cron: '0 3 * * 1'
jobs:
analyze:
name: Analyze (java)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
cache: gradle
distribution: temurin
java-version: "17"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
- name: Grant Execute Permission
run: chmod +x ./gradlew
- name: Build
run: ./gradlew assembleDebug --stacktrace
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: /language:${{ matrix.language }}
timeout-minutes: "30"
strategy:
fail-fast: "false"
matrix:
language:
- java
permissions:
actions: read
contents: read
security-events: write
...
|
analyze
|
null
|
["ubuntu-latest"]
|
26963
|
2
|
1779073403
|
1779073438
|
1779073228
|
1779073438
|
|
0
|
|
0
|
Edit
Delete
|
|
30837
|
23385
|
6
|
5
|
abd9c78e81e375b307f84a5333bb2006694b6844
|
0
|
Governance Audit (HARD GATE)
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_OPTIONS: --max-old-space-size=8192
NODE_VERSION: "20"
jobs:
governance-audit:
name: Governance Audit (HARD GATE)
runs-on: ubuntu-latest
steps:
- uses: https://gitea.com/actions/checkout@v4
- uses: https://gitea.com/pnpm/action-setup@v4
- uses: https://gitea.com/actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile --ignore-scripts
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Audit 多租户隔离(HARD GATE / 红线1,不豁免)
run: pnpm -C backend run audit:tenant
- name: Audit Prisma↔Zod 契约
run: pnpm -C backend exec tsx scripts/audit-prisma-zod-contract.ts
continue-on-error: true
- name: Audit FormRules↔Zod
run: pnpm run audit:formrules-zod
continue-on-error: true
- name: Audit Response Columns
run: pnpm run audit:response-columns
continue-on-error: true
- name: Audit Field Payload
run: pnpm run audit:field-payload
continue-on-error: true
- name: Audit Enum Consistency
run: pnpm run audit:enum-consistency
continue-on-error: true
- name: Audit useListPage ↔ Router
run: pnpm run audit:list-page-routes
continue-on-error: true
- name: Audit Page AI Assist Coverage
run: pnpm run audit:ai-assist-coverage
continue-on-error: true
- name: Audit Page AI Assist Skill Binding
run: pnpm run audit:ai-assist-skill-binding
continue-on-error: true
- name: Audit Page AI Assist Context Providers
run: pnpm run audit:context-provider-redact
continue-on-error: true
- name: Audit Coach Script Library
run: pnpm run audit:coach-script-library
continue-on-error: true
- name: Audit AI Decision Quality
run: pnpm run audit:ai-decision-quality
continue-on-error: true
- name: Audit Event Publishing
run: pnpm -C backend run audit:events
continue-on-error: true
- name: Audit State Machines
run: pnpm -C backend run audit:state-machines
continue-on-error: true
- name: Audit Money Decimal Purity (CFO-P0 防御)
run: node --import tsx scripts/audit-money-decimal-purity.ts
continue-on-error: true
- name: Audit Nested Transaction (CFO-P0-1 + RO-P0-3 防御)
run: node --import tsx scripts/audit-nested-transaction.ts
continue-on-error: true
- name: Audit Test Assertion Density (QA-P0 防御)
run: node --import tsx scripts/audit-test-assertion-density.ts
continue-on-error: true
- name: Audit API Test Coverage (probe-only / read-covered / action-covered / complete-crud)
run: pnpm -C backend run audit:api-test-coverage
continue-on-error: true
- name: Harness Report 聚合
run: pnpm harness report --save
continue-on-error: true
- if: always()
name: Upload audit reports
uses: https://gitea.com/actions/upload-artifact@v3
with:
name: governance-audit-reports
path: |
reports/prisma-zod-contract-audit.latest.json
reports/formrules-zod-audit.latest.json
reports/response-columns-audit.latest.json
reports/field-payload-audit.latest.json
reports/enum-consistency-audit.latest.json
reports/list-page-routes-audit.latest.json
reports/ai-assist-coverage.latest.json
reports/ai-assist-skill-binding.latest.json
reports/ai-assist-context-providers.latest.json
reports/coach-script-library.latest.json
reports/ai-decision-quality.latest.json
reports/event-publishing-audit.latest.json
reports/state-machine-integration-audit.latest.json
reports/harness-dashboard.latest.json
reports/module-grades.latest.json
reports/money-decimal-purity-audit.latest.json
reports/nested-transaction-audit.latest.json
reports/test-assertion-density-audit.latest.json
reports/api-test-coverage.latest.json
retention-days: "14"
- if: always()
name: 输出 governance summary
run: |
if [ -f reports/harness-dashboard.latest.json ]; then
node -e "
const d = require('./reports/harness-dashboard.latest.json');
const s = d.summary || {};
const lines = [
'## Governance Audit Summary',
'',
'| Severity | Count |',
'|---|---|',
\`| CRITICAL | \${s.critical ?? 0} |\`,
\`| HIGH | \${s.high ?? 0} |\`,
\`| MEDIUM | \${s.medium ?? 0} |\`,
\`| LOW | \${s.low ?? 0} |\`,
\`| INFO | \${s.info ?? 0} |\`,
'',
\`- 总 finding: \${s.total ?? 0}\`,
\`- 涉及模块: \${s.modulesAffected ?? 0}\`,
\`- 审计执行: \${s.auditsRun ?? 0}\`,
\`- 审计 missing: \${s.reportsMissing ?? 0}\`,
\`- 审计 stale (>7d): \${s.reportsStale ?? 0}\`,
\`- 审计 invalid: \${s.reportsInvalid ?? 0}\`,
'',
'**门禁规则:HIGH+CRITICAL+MEDIUM 必须为 0,且 reportsMissing/Stale/Invalid 必须为 0。**',
];
const fs = require('fs');
const out = process.env.GITHUB_STEP_SUMMARY;
if (out) fs.appendFileSync(out, lines.join('\n') + '\n');
else console.log(lines.join('\n'));
"
else
echo '⚠️ harness-dashboard.latest.json 未生成,治理门禁判定失败'
fi
- name: 治理硬门禁 — 豁免感知 verdict(HARD)
run: node --import tsx scripts/harness/governance-gate.ts
- name: 文档对账 — CLAUDE.md GOVERNANCE-BASELINE ↔ reports 实测(HARD)
run: node --import tsx scripts/harness/baseline-reconcile.ts
- name: Harness Gate 综合 PR 验收(HARD)
run: pnpm harness gate
...
|
governance-audit
|
["lint-and-typecheck"]
|
["ubuntu-latest"]
|
26981
|
2
|
1779507035
|
1779507390
|
1779504053
|
1779507390
|
|
1
|
|
0
|
Edit
Delete
|
|
30842
|
23386
|
6
|
5
|
bd6b20a8cdf6b23a3c68d2a8717c1bcfb60f3870
|
0
|
Governance Audit (HARD GATE)
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_OPTIONS: --max-old-space-size=8192
NODE_VERSION: "20"
jobs:
governance-audit:
name: Governance Audit (HARD GATE)
runs-on: ubuntu-latest
steps:
- uses: https://gitea.com/actions/checkout@v4
- uses: https://gitea.com/pnpm/action-setup@v4
- uses: https://gitea.com/actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile --ignore-scripts
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Audit 多租户隔离(HARD GATE / 红线1,不豁免)
run: pnpm -C backend run audit:tenant
- name: Audit Prisma↔Zod 契约
run: pnpm -C backend exec tsx scripts/audit-prisma-zod-contract.ts
continue-on-error: true
- name: Audit FormRules↔Zod
run: pnpm run audit:formrules-zod
continue-on-error: true
- name: Audit Response Columns
run: pnpm run audit:response-columns
continue-on-error: true
- name: Audit Field Payload
run: pnpm run audit:field-payload
continue-on-error: true
- name: Audit Enum Consistency
run: pnpm run audit:enum-consistency
continue-on-error: true
- name: Audit useListPage ↔ Router
run: pnpm run audit:list-page-routes
continue-on-error: true
- name: Audit Page AI Assist Coverage
run: pnpm run audit:ai-assist-coverage
continue-on-error: true
- name: Audit Page AI Assist Skill Binding
run: pnpm run audit:ai-assist-skill-binding
continue-on-error: true
- name: Audit Page AI Assist Context Providers
run: pnpm run audit:context-provider-redact
continue-on-error: true
- name: Audit Coach Script Library
run: pnpm run audit:coach-script-library
continue-on-error: true
- name: Audit AI Decision Quality
run: pnpm run audit:ai-decision-quality
continue-on-error: true
- name: Audit Event Publishing
run: pnpm -C backend run audit:events
continue-on-error: true
- name: Audit State Machines
run: pnpm -C backend run audit:state-machines
continue-on-error: true
- name: Audit Money Decimal Purity (CFO-P0 防御)
run: node --import tsx scripts/audit-money-decimal-purity.ts
continue-on-error: true
- name: Audit Nested Transaction (CFO-P0-1 + RO-P0-3 防御)
run: node --import tsx scripts/audit-nested-transaction.ts
continue-on-error: true
- name: Audit Test Assertion Density (QA-P0 防御)
run: node --import tsx scripts/audit-test-assertion-density.ts
continue-on-error: true
- name: Audit API Test Coverage (probe-only / read-covered / action-covered / complete-crud)
run: pnpm -C backend run audit:api-test-coverage
continue-on-error: true
- name: Harness Report 聚合
run: pnpm harness report --save
continue-on-error: true
- if: always()
name: Upload audit reports
uses: https://gitea.com/actions/upload-artifact@v3
with:
name: governance-audit-reports
path: |
reports/prisma-zod-contract-audit.latest.json
reports/formrules-zod-audit.latest.json
reports/response-columns-audit.latest.json
reports/field-payload-audit.latest.json
reports/enum-consistency-audit.latest.json
reports/list-page-routes-audit.latest.json
reports/ai-assist-coverage.latest.json
reports/ai-assist-skill-binding.latest.json
reports/ai-assist-context-providers.latest.json
reports/coach-script-library.latest.json
reports/ai-decision-quality.latest.json
reports/event-publishing-audit.latest.json
reports/state-machine-integration-audit.latest.json
reports/harness-dashboard.latest.json
reports/module-grades.latest.json
reports/money-decimal-purity-audit.latest.json
reports/nested-transaction-audit.latest.json
reports/test-assertion-density-audit.latest.json
reports/api-test-coverage.latest.json
retention-days: "14"
- if: always()
name: 输出 governance summary
run: |
if [ -f reports/harness-dashboard.latest.json ]; then
node -e "
const d = require('./reports/harness-dashboard.latest.json');
const s = d.summary || {};
const lines = [
'## Governance Audit Summary',
'',
'| Severity | Count |',
'|---|---|',
\`| CRITICAL | \${s.critical ?? 0} |\`,
\`| HIGH | \${s.high ?? 0} |\`,
\`| MEDIUM | \${s.medium ?? 0} |\`,
\`| LOW | \${s.low ?? 0} |\`,
\`| INFO | \${s.info ?? 0} |\`,
'',
\`- 总 finding: \${s.total ?? 0}\`,
\`- 涉及模块: \${s.modulesAffected ?? 0}\`,
\`- 审计执行: \${s.auditsRun ?? 0}\`,
\`- 审计 missing: \${s.reportsMissing ?? 0}\`,
\`- 审计 stale (>7d): \${s.reportsStale ?? 0}\`,
\`- 审计 invalid: \${s.reportsInvalid ?? 0}\`,
'',
'**门禁规则:HIGH+CRITICAL+MEDIUM 必须为 0,且 reportsMissing/Stale/Invalid 必须为 0。**',
];
const fs = require('fs');
const out = process.env.GITHUB_STEP_SUMMARY;
if (out) fs.appendFileSync(out, lines.join('\n') + '\n');
else console.log(lines.join('\n'));
"
else
echo '⚠️ harness-dashboard.latest.json 未生成,治理门禁判定失败'
fi
- name: 治理硬门禁 — 豁免感知 verdict(HARD)
run: node --import tsx scripts/harness/governance-gate.ts
- name: 文档对账 — CLAUDE.md GOVERNANCE-BASELINE ↔ reports 实测(HARD)
run: node --import tsx scripts/harness/baseline-reconcile.ts
- name: Harness Gate 综合 PR 验收(HARD)
run: pnpm harness gate
...
|
governance-audit
|
["lint-and-typecheck"]
|
["ubuntu-latest"]
|
26983
|
2
|
1779507959
|
1779508458
|
1779504065
|
1779508458
|
|
1
|
|
0
|
Edit
Delete
|
|
30844
|
23387
|
13
|
5
|
6c80c00976d1c5ac4aaa5f76d10cf1e7b4f59448
|
0
|
Analyze (java)
|
1
|
name: CodeQL Analysis
"on":
push:
name: CodeQL Analysis
"on":
push:
branches: [develop, master, main]
pull_request:
branches: [develop, master, main]
schedule:
# 每周一凌晨3点运行
- cron: '0 3 * * 1'
jobs:
analyze:
name: Analyze (java)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
cache: gradle
distribution: temurin
java-version: "17"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
- name: Grant Execute Permission
run: chmod +x ./gradlew
- name: Build
run: ./gradlew assembleDebug --stacktrace
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: /language:${{ matrix.language }}
timeout-minutes: "30"
strategy:
fail-fast: "false"
matrix:
language:
- java
permissions:
actions: read
contents: read
security-events: write
...
|
analyze
|
null
|
["ubuntu-latest"]
|
26984
|
2
|
1779678028
|
1779678118
|
1779678028
|
1779678119
|
|
0
|
|
0
|
Edit
Delete
|
|
30847
|
23388
|
6
|
5
|
7bff77f02f58e23bad0ebcbdbb262111707628e7
|
0
|
Unit Tests (HARD GATE)
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_OPTIONS: --max-old-space-size=8192
NODE_VERSION: "20"
jobs:
unit-tests:
name: Unit Tests (HARD GATE)
runs-on: ubuntu-latest
steps:
- uses: https://gitea.com/actions/checkout@v4
- uses: https://gitea.com/pnpm/action-setup@v4
- uses: https://gitea.com/actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile --ignore-scripts
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Run unit tests
run: pnpm -C backend run test:unit
...
|
unit-tests
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck"]...
|
["ubuntu-latest"]
|
26988
|
2
|
1779685825
|
1779686361
|
1779684792
|
1779686361
|
|
1
|
|
0
|
Edit
Delete
|
|
30848
|
23388
|
6
|
5
|
7bff77f02f58e23bad0ebcbdbb262111707628e7
|
0
|
Governance Audit (HARD GATE)
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_OPTIONS: --max-old-space-size=8192
NODE_VERSION: "20"
jobs:
governance-audit:
name: Governance Audit (HARD GATE)
runs-on: ubuntu-latest
steps:
- uses: https://gitea.com/actions/checkout@v4
- uses: https://gitea.com/pnpm/action-setup@v4
- uses: https://gitea.com/actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile --ignore-scripts
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Audit 多租户隔离(HARD GATE / 红线1,不豁免)
run: pnpm -C backend run audit:tenant
- name: Audit Prisma↔Zod 契约
run: pnpm -C backend exec tsx scripts/audit-prisma-zod-contract.ts
continue-on-error: true
- name: Audit FormRules↔Zod
run: pnpm run audit:formrules-zod
continue-on-error: true
- name: Audit Response Columns
run: pnpm run audit:response-columns
continue-on-error: true
- name: Audit Field Payload
run: pnpm run audit:field-payload
continue-on-error: true
- name: Audit Enum Consistency
run: pnpm run audit:enum-consistency
continue-on-error: true
- name: Audit useListPage ↔ Router
run: pnpm run audit:list-page-routes
continue-on-error: true
- name: Audit Page AI Assist Coverage
run: pnpm run audit:ai-assist-coverage
continue-on-error: true
- name: Audit Page AI Assist Skill Binding
run: pnpm run audit:ai-assist-skill-binding
continue-on-error: true
- name: Audit Page AI Assist Context Providers
run: pnpm run audit:context-provider-redact
continue-on-error: true
- name: Audit Coach Script Library
run: pnpm run audit:coach-script-library
continue-on-error: true
- name: Audit AI Decision Quality
run: pnpm run audit:ai-decision-quality
continue-on-error: true
- name: Audit Event Publishing
run: pnpm -C backend run audit:events
continue-on-error: true
- name: Audit State Machines
run: pnpm -C backend run audit:state-machines
continue-on-error: true
- name: Audit Money Decimal Purity (CFO-P0 防御)
run: node --import tsx scripts/audit-money-decimal-purity.ts
continue-on-error: true
- name: Audit Nested Transaction (CFO-P0-1 + RO-P0-3 防御)
run: node --import tsx scripts/audit-nested-transaction.ts
continue-on-error: true
- name: Audit Test Assertion Density (QA-P0 防御)
run: node --import tsx scripts/audit-test-assertion-density.ts
continue-on-error: true
- name: Audit API Test Coverage (probe-only / read-covered / action-covered / complete-crud)
run: pnpm -C backend run audit:api-test-coverage
continue-on-error: true
- name: Harness Report 聚合
run: pnpm harness report --save
continue-on-error: true
- if: always()
name: Upload audit reports
uses: https://gitea.com/actions/upload-artifact@v3
with:
name: governance-audit-reports
path: |
reports/prisma-zod-contract-audit.latest.json
reports/formrules-zod-audit.latest.json
reports/response-columns-audit.latest.json
reports/field-payload-audit.latest.json
reports/enum-consistency-audit.latest.json
reports/list-page-routes-audit.latest.json
reports/ai-assist-coverage.latest.json
reports/ai-assist-skill-binding.latest.json
reports/ai-assist-context-providers.latest.json
reports/coach-script-library.latest.json
reports/ai-decision-quality.latest.json
reports/event-publishing-audit.latest.json
reports/state-machine-integration-audit.latest.json
reports/harness-dashboard.latest.json
reports/module-grades.latest.json
reports/money-decimal-purity-audit.latest.json
reports/nested-transaction-audit.latest.json
reports/test-assertion-density-audit.latest.json
reports/api-test-coverage.latest.json
retention-days: "14"
- if: always()
name: 输出 governance summary
run: |
if [ -f reports/harness-dashboard.latest.json ]; then
node -e "
const d = require('./reports/harness-dashboard.latest.json');
const s = d.summary || {};
const lines = [
'## Governance Audit Summary',
'',
'| Severity | Count |',
'|---|---|',
\`| CRITICAL | \${s.critical ?? 0} |\`,
\`| HIGH | \${s.high ?? 0} |\`,
\`| MEDIUM | \${s.medium ?? 0} |\`,
\`| LOW | \${s.low ?? 0} |\`,
\`| INFO | \${s.info ?? 0} |\`,
'',
\`- 总 finding: \${s.total ?? 0}\`,
\`- 涉及模块: \${s.modulesAffected ?? 0}\`,
\`- 审计执行: \${s.auditsRun ?? 0}\`,
\`- 审计 missing: \${s.reportsMissing ?? 0}\`,
\`- 审计 stale (>7d): \${s.reportsStale ?? 0}\`,
\`- 审计 invalid: \${s.reportsInvalid ?? 0}\`,
'',
'**门禁规则:HIGH+CRITICAL+MEDIUM 必须为 0,且 reportsMissing/Stale/Invalid 必须为 0。**',
];
const fs = require('fs');
const out = process.env.GITHUB_STEP_SUMMARY;
if (out) fs.appendFileSync(out, lines.join('\n') + '\n');
else console.log(lines.join('\n'));
"
else
echo '⚠️ harness-dashboard.latest.json 未生成,治理门禁判定失败'
fi
- name: 治理硬门禁 — 豁免感知 verdict(HARD)
run: node --import tsx scripts/harness/governance-gate.ts
- name: 文档对账 — CLAUDE.md GOVERNANCE-BASELINE ↔ reports 实测(HARD)
run: node --import tsx scripts/harness/baseline-reconcile.ts
- name: Harness Gate 综合 PR 验收(HARD)
run: pnpm harness gate
...
|
governance-audit
|
["lint-and-typecheck"]
|
["ubuntu-latest"]
|
26989
|
2
|
1779686361
|
1779686657
|
1779684792
|
1779686657
|
|
1
|
|
0
|
Edit
Delete
|
|
30852
|
23389
|
6
|
5
|
d9e0ab1d9cbc0d7707781f8b0c9a5a49103ace8b
|
0
|
Unit Tests (HARD GATE)
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_OPTIONS: --max-old-space-size=8192
NODE_VERSION: "20"
jobs:
unit-tests:
name: Unit Tests (HARD GATE)
runs-on: ubuntu-latest
steps:
- uses: https://gitea.com/actions/checkout@v4
- uses: https://gitea.com/pnpm/action-setup@v4
- uses: https://gitea.com/actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile --ignore-scripts
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Run unit tests
run: pnpm -C backend run test:unit
...
|
unit-tests
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck"]...
|
["ubuntu-latest"]
|
26993
|
2
|
1779688278
|
1779688812
|
1779687046
|
1779688812
|
|
1
|
|
0
|
Edit
Delete
|
|
30853
|
23389
|
6
|
5
|
d9e0ab1d9cbc0d7707781f8b0c9a5a49103ace8b
|
0
|
Governance Audit (HARD GATE)
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_OPTIONS: --max-old-space-size=8192
NODE_VERSION: "20"
jobs:
governance-audit:
name: Governance Audit (HARD GATE)
runs-on: ubuntu-latest
steps:
- uses: https://gitea.com/actions/checkout@v4
- uses: https://gitea.com/pnpm/action-setup@v4
- uses: https://gitea.com/actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile --ignore-scripts
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Audit 多租户隔离(HARD GATE / 红线1,不豁免)
run: pnpm -C backend run audit:tenant
- name: Audit Prisma↔Zod 契约
run: pnpm -C backend exec tsx scripts/audit-prisma-zod-contract.ts
continue-on-error: true
- name: Audit FormRules↔Zod
run: pnpm run audit:formrules-zod
continue-on-error: true
- name: Audit Response Columns
run: pnpm run audit:response-columns
continue-on-error: true
- name: Audit Field Payload
run: pnpm run audit:field-payload
continue-on-error: true
- name: Audit Enum Consistency
run: pnpm run audit:enum-consistency
continue-on-error: true
- name: Audit useListPage ↔ Router
run: pnpm run audit:list-page-routes
continue-on-error: true
- name: Audit Page AI Assist Coverage
run: pnpm run audit:ai-assist-coverage
continue-on-error: true
- name: Audit Page AI Assist Skill Binding
run: pnpm run audit:ai-assist-skill-binding
continue-on-error: true
- name: Audit Page AI Assist Context Providers
run: pnpm run audit:context-provider-redact
continue-on-error: true
- name: Audit Coach Script Library
run: pnpm run audit:coach-script-library
continue-on-error: true
- name: Audit AI Decision Quality
run: pnpm run audit:ai-decision-quality
continue-on-error: true
- name: Audit Event Publishing
run: pnpm -C backend run audit:events
continue-on-error: true
- name: Audit State Machines
run: pnpm -C backend run audit:state-machines
continue-on-error: true
- name: Audit Money Decimal Purity (CFO-P0 防御)
run: node --import tsx scripts/audit-money-decimal-purity.ts
continue-on-error: true
- name: Audit Nested Transaction (CFO-P0-1 + RO-P0-3 防御)
run: node --import tsx scripts/audit-nested-transaction.ts
continue-on-error: true
- name: Audit Test Assertion Density (QA-P0 防御)
run: node --import tsx scripts/audit-test-assertion-density.ts
continue-on-error: true
- name: Audit API Test Coverage (probe-only / read-covered / action-covered / complete-crud)
run: pnpm -C backend run audit:api-test-coverage
continue-on-error: true
- name: Harness Report 聚合
run: pnpm harness report --save
continue-on-error: true
- if: always()
name: Upload audit reports
uses: https://gitea.com/actions/upload-artifact@v3
with:
name: governance-audit-reports
path: |
reports/prisma-zod-contract-audit.latest.json
reports/formrules-zod-audit.latest.json
reports/response-columns-audit.latest.json
reports/field-payload-audit.latest.json
reports/enum-consistency-audit.latest.json
reports/list-page-routes-audit.latest.json
reports/ai-assist-coverage.latest.json
reports/ai-assist-skill-binding.latest.json
reports/ai-assist-context-providers.latest.json
reports/coach-script-library.latest.json
reports/ai-decision-quality.latest.json
reports/event-publishing-audit.latest.json
reports/state-machine-integration-audit.latest.json
reports/harness-dashboard.latest.json
reports/module-grades.latest.json
reports/money-decimal-purity-audit.latest.json
reports/nested-transaction-audit.latest.json
reports/test-assertion-density-audit.latest.json
reports/api-test-coverage.latest.json
retention-days: "14"
- if: always()
name: 输出 governance summary
run: |
if [ -f reports/harness-dashboard.latest.json ]; then
node -e "
const d = require('./reports/harness-dashboard.latest.json');
const s = d.summary || {};
const lines = [
'## Governance Audit Summary',
'',
'| Severity | Count |',
'|---|---|',
\`| CRITICAL | \${s.critical ?? 0} |\`,
\`| HIGH | \${s.high ?? 0} |\`,
\`| MEDIUM | \${s.medium ?? 0} |\`,
\`| LOW | \${s.low ?? 0} |\`,
\`| INFO | \${s.info ?? 0} |\`,
'',
\`- 总 finding: \${s.total ?? 0}\`,
\`- 涉及模块: \${s.modulesAffected ?? 0}\`,
\`- 审计执行: \${s.auditsRun ?? 0}\`,
\`- 审计 missing: \${s.reportsMissing ?? 0}\`,
\`- 审计 stale (>7d): \${s.reportsStale ?? 0}\`,
\`- 审计 invalid: \${s.reportsInvalid ?? 0}\`,
'',
'**门禁规则:HIGH+CRITICAL+MEDIUM 必须为 0,且 reportsMissing/Stale/Invalid 必须为 0。**',
];
const fs = require('fs');
const out = process.env.GITHUB_STEP_SUMMARY;
if (out) fs.appendFileSync(out, lines.join('\n') + '\n');
else console.log(lines.join('\n'));
"
else
echo '⚠️ harness-dashboard.latest.json 未生成,治理门禁判定失败'
fi
- name: 治理硬门禁 — 豁免感知 verdict(HARD)
run: node --import tsx scripts/harness/governance-gate.ts
- name: 文档对账 — CLAUDE.md GOVERNANCE-BASELINE ↔ reports 实测(HARD)
run: node --import tsx scripts/harness/baseline-reconcile.ts
- name: Harness Gate 综合 PR 验收(HARD)
run: pnpm harness gate
...
|
governance-audit
|
["lint-and-typecheck"]
|
["ubuntu-latest"]
|
26994
|
2
|
1779688812
|
1779689247
|
1779687046
|
1779689247
|
|
1
|
|
0
|
Edit
Delete
|
|
30857
|
23390
|
6
|
5
|
91f125bd289d82c469493539589d79318bb96269
|
0
|
Unit Tests (HARD GATE)
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_OPTIONS: --max-old-space-size=8192
NODE_VERSION: "20"
jobs:
unit-tests:
name: Unit Tests (HARD GATE)
runs-on: ubuntu-latest
steps:
- uses: https://gitea.com/actions/checkout@v4
- uses: https://gitea.com/pnpm/action-setup@v4
- uses: https://gitea.com/actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile --ignore-scripts
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Run unit tests
run: pnpm -C backend run test:unit
...
|
unit-tests
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck"]...
|
["ubuntu-latest"]
|
26998
|
2
|
1779787721
|
1779788257
|
1779786701
|
1779788257
|
|
1
|
|
0
|
Edit
Delete
|
|
30858
|
23390
|
6
|
5
|
91f125bd289d82c469493539589d79318bb96269
|
0
|
Governance Audit (HARD GATE)
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_OPTIONS: --max-old-space-size=8192
NODE_VERSION: "20"
jobs:
governance-audit:
name: Governance Audit (HARD GATE)
runs-on: ubuntu-latest
steps:
- uses: https://gitea.com/actions/checkout@v4
- uses: https://gitea.com/pnpm/action-setup@v4
- uses: https://gitea.com/actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile --ignore-scripts
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Audit 多租户隔离(HARD GATE / 红线1,不豁免)
run: pnpm -C backend run audit:tenant
- name: Audit Prisma↔Zod 契约
run: pnpm -C backend exec tsx scripts/audit-prisma-zod-contract.ts
continue-on-error: true
- name: Audit FormRules↔Zod
run: pnpm run audit:formrules-zod
continue-on-error: true
- name: Audit Response Columns
run: pnpm run audit:response-columns
continue-on-error: true
- name: Audit Field Payload
run: pnpm run audit:field-payload
continue-on-error: true
- name: Audit Enum Consistency
run: pnpm run audit:enum-consistency
continue-on-error: true
- name: Audit useListPage ↔ Router
run: pnpm run audit:list-page-routes
continue-on-error: true
- name: Audit Page AI Assist Coverage
run: pnpm run audit:ai-assist-coverage
continue-on-error: true
- name: Audit Page AI Assist Skill Binding
run: pnpm run audit:ai-assist-skill-binding
continue-on-error: true
- name: Audit Page AI Assist Context Providers
run: pnpm run audit:context-provider-redact
continue-on-error: true
- name: Audit Coach Script Library
run: pnpm run audit:coach-script-library
continue-on-error: true
- name: Audit AI Decision Quality
run: pnpm run audit:ai-decision-quality
continue-on-error: true
- name: Audit Event Publishing
run: pnpm -C backend run audit:events
continue-on-error: true
- name: Audit State Machines
run: pnpm -C backend run audit:state-machines
continue-on-error: true
- name: Audit Money Decimal Purity (CFO-P0 防御)
run: node --import tsx scripts/audit-money-decimal-purity.ts
continue-on-error: true
- name: Audit Nested Transaction (CFO-P0-1 + RO-P0-3 防御)
run: node --import tsx scripts/audit-nested-transaction.ts
continue-on-error: true
- name: Audit Test Assertion Density (QA-P0 防御)
run: node --import tsx scripts/audit-test-assertion-density.ts
continue-on-error: true
- name: Audit API Test Coverage (probe-only / read-covered / action-covered / complete-crud)
run: pnpm -C backend run audit:api-test-coverage
continue-on-error: true
- name: Harness Report 聚合
run: pnpm harness report --save
continue-on-error: true
- if: always()
name: Upload audit reports
uses: https://gitea.com/actions/upload-artifact@v3
with:
name: governance-audit-reports
path: |
reports/prisma-zod-contract-audit.latest.json
reports/formrules-zod-audit.latest.json
reports/response-columns-audit.latest.json
reports/field-payload-audit.latest.json
reports/enum-consistency-audit.latest.json
reports/list-page-routes-audit.latest.json
reports/ai-assist-coverage.latest.json
reports/ai-assist-skill-binding.latest.json
reports/ai-assist-context-providers.latest.json
reports/coach-script-library.latest.json
reports/ai-decision-quality.latest.json
reports/event-publishing-audit.latest.json
reports/state-machine-integration-audit.latest.json
reports/harness-dashboard.latest.json
reports/module-grades.latest.json
reports/money-decimal-purity-audit.latest.json
reports/nested-transaction-audit.latest.json
reports/test-assertion-density-audit.latest.json
reports/api-test-coverage.latest.json
retention-days: "14"
- if: always()
name: 输出 governance summary
run: |
if [ -f reports/harness-dashboard.latest.json ]; then
node -e "
const d = require('./reports/harness-dashboard.latest.json');
const s = d.summary || {};
const lines = [
'## Governance Audit Summary',
'',
'| Severity | Count |',
'|---|---|',
\`| CRITICAL | \${s.critical ?? 0} |\`,
\`| HIGH | \${s.high ?? 0} |\`,
\`| MEDIUM | \${s.medium ?? 0} |\`,
\`| LOW | \${s.low ?? 0} |\`,
\`| INFO | \${s.info ?? 0} |\`,
'',
\`- 总 finding: \${s.total ?? 0}\`,
\`- 涉及模块: \${s.modulesAffected ?? 0}\`,
\`- 审计执行: \${s.auditsRun ?? 0}\`,
\`- 审计 missing: \${s.reportsMissing ?? 0}\`,
\`- 审计 stale (>7d): \${s.reportsStale ?? 0}\`,
\`- 审计 invalid: \${s.reportsInvalid ?? 0}\`,
'',
'**门禁规则:HIGH+CRITICAL+MEDIUM 必须为 0,且 reportsMissing/Stale/Invalid 必须为 0。**',
];
const fs = require('fs');
const out = process.env.GITHUB_STEP_SUMMARY;
if (out) fs.appendFileSync(out, lines.join('\n') + '\n');
else console.log(lines.join('\n'));
"
else
echo '⚠️ harness-dashboard.latest.json 未生成,治理门禁判定失败'
fi
- name: 治理硬门禁 — 豁免感知 verdict(HARD)
run: node --import tsx scripts/harness/governance-gate.ts
- name: 文档对账 — CLAUDE.md GOVERNANCE-BASELINE ↔ reports 实测(HARD)
run: node --import tsx scripts/harness/baseline-reconcile.ts
- name: Harness Gate 综合 PR 验收(HARD)
run: pnpm harness gate
...
|
governance-audit
|
["lint-and-typecheck"]
|
["ubuntu-latest"]
|
26999
|
2
|
1779788257
|
1779788550
|
1779786701
|
1779788550
|
|
1
|
|
0
|
Edit
Delete
|
|
30860
|
23391
|
13
|
5
|
6c80c00976d1c5ac4aaa5f76d10cf1e7b4f59448
|
0
|
Analyze (java)
|
1
|
name: CodeQL Analysis
"on":
push:
name: CodeQL Analysis
"on":
push:
branches: [develop, master, main]
pull_request:
branches: [develop, master, main]
schedule:
# 每周一凌晨3点运行
- cron: '0 3 * * 1'
jobs:
analyze:
name: Analyze (java)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
cache: gradle
distribution: temurin
java-version: "17"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
- name: Grant Execute Permission
run: chmod +x ./gradlew
- name: Build
run: ./gradlew assembleDebug --stacktrace
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: /language:${{ matrix.language }}
timeout-minutes: "30"
strategy:
fail-fast: "false"
matrix:
language:
- java
permissions:
actions: read
contents: read
security-events: write
...
|
analyze
|
null
|
["ubuntu-latest"]
|
27000
|
2
|
1780282828
|
1780282919
|
1780282828
|
1780282919
|
|
0
|
|
0
|
Edit
Delete
|
|
30861
|
23392
|
13
|
5
|
6c80c00976d1c5ac4aaa5f76d10cf1e7b4f59448
|
0
|
Analyze (java)
|
1
|
name: CodeQL Analysis
"on":
push:
name: CodeQL Analysis
"on":
push:
branches: [develop, master, main]
pull_request:
branches: [develop, master, main]
schedule:
# 每周一凌晨3点运行
- cron: '0 3 * * 1'
jobs:
analyze:
name: Analyze (java)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
cache: gradle
distribution: temurin
java-version: "17"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
- name: Grant Execute Permission
run: chmod +x ./gradlew
- name: Build
run: ./gradlew assembleDebug --stacktrace
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: /language:${{ matrix.language }}
timeout-minutes: "30"
strategy:
fail-fast: "false"
matrix:
language:
- java
permissions:
actions: read
contents: read
security-events: write
...
|
analyze
|
null
|
["ubuntu-latest"]
|
27001
|
2
|
1780887629
|
1780887670
|
1780887628
|
1780887670
|
|
0
|
|
0
|
Edit
Delete
|
|
30864
|
23393
|
6
|
5
|
c32dc69661d18fedc3e6939936535f3f5906bf7d
|
0
|
Unit Tests (HARD GATE)
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_OPTIONS: --max-old-space-size=8192
NODE_VERSION: "20"
jobs:
unit-tests:
name: Unit Tests (HARD GATE)
runs-on: ubuntu-latest
steps:
- uses: https://gitea.com/actions/checkout@v4
- uses: https://gitea.com/pnpm/action-setup@v4
- uses: https://gitea.com/actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile --ignore-scripts
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Run unit tests
run: pnpm -C backend run test:unit
...
|
unit-tests
|
["frontend-typecheck","lint-and-typech ["frontend-typecheck","lint-and-typecheck"]...
|
["ubuntu-latest"]
|
27005
|
2
|
1780926013
|
1780926415
|
1780924423
|
1780926415
|
|
1
|
|
0
|
Edit
Delete
|
|
30866
|
23393
|
6
|
5
|
c32dc69661d18fedc3e6939936535f3f5906bf7d
|
0
|
Governance Audit (HARD GATE)
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_OPTIONS: --max-old-space-size=8192
NODE_VERSION: "20"
jobs:
governance-audit:
name: Governance Audit (HARD GATE)
runs-on: ubuntu-latest
steps:
- uses: https://gitea.com/actions/checkout@v4
- uses: https://gitea.com/pnpm/action-setup@v4
- uses: https://gitea.com/actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- run: pnpm install --frozen-lockfile --ignore-scripts
- name: Generate Prisma Client
run: pnpm -C backend exec prisma generate
- name: Build shared package
run: pnpm -C shared run build
- name: Audit 多租户隔离(HARD GATE / 红线1,不豁免)
run: pnpm -C backend run audit:tenant
- name: Audit Prisma Schema 镜像一致性(HARD GATE)
run: pnpm run audit:prisma-schema-source
- name: Audit Prisma↔Zod 契约
run: pnpm -C backend exec tsx scripts/audit-prisma-zod-contract.ts
continue-on-error: true
- name: Audit FormRules↔Zod
run: pnpm run audit:formrules-zod
continue-on-error: true
- name: Audit Response Columns
run: pnpm run audit:response-columns
continue-on-error: true
- name: Audit Field Payload
run: pnpm run audit:field-payload
continue-on-error: true
- name: Audit Enum Consistency
run: pnpm run audit:enum-consistency
continue-on-error: true
- name: Audit useListPage ↔ Router
run: pnpm run audit:list-page-routes
continue-on-error: true
- name: Audit 前端权限键 ↔ 后端真源(HARD GATE / 防按钮 fail-closed 隐藏)
run: pnpm run audit:permission-keys
- name: Audit Page AI Assist Coverage
run: pnpm run audit:ai-assist-coverage
continue-on-error: true
- name: Audit Page AI Assist Skill Binding
run: pnpm run audit:ai-assist-skill-binding
continue-on-error: true
- name: Audit Page AI Assist Context Providers
run: pnpm run audit:context-provider-redact
continue-on-error: true
- name: Audit Coach Script Library
run: pnpm run audit:coach-script-library
continue-on-error: true
- name: Audit AI Decision Quality
run: pnpm run audit:ai-decision-quality
continue-on-error: true
- name: Audit Event Publishing
run: pnpm -C backend run audit:events
continue-on-error: true
- name: Audit State Machines
run: pnpm -C backend run audit:state-machines
continue-on-error: true
- name: Audit Money Decimal Purity (CFO-P0 防御)
run: node --import tsx scripts/audit-money-decimal-purity.ts
continue-on-error: true
- name: Audit Nested Transaction (CFO-P0-1 + RO-P0-3 防御)
run: node --import tsx scripts/audit-nested-transaction.ts
continue-on-error: true
- name: Audit Test Assertion Density (QA-P0 防御)
run: node --import tsx scripts/audit-test-assertion-density.ts
continue-on-error: true
- name: Audit API Test Coverage (probe-only / read-covered / action-covered / complete-crud)
run: pnpm -C backend run audit:api-test-coverage
continue-on-error: true
- name: Audit Consumer Test Authenticity (断言剧场防御 / 假绿防御)
run: node --import tsx scripts/audit-consumer-test-authenticity.ts
continue-on-error: true
- name: Audit Consumer Idempotency (去重路径假覆盖防御)
run: node --import tsx scripts/audit-consumer-idempotency.ts
continue-on-error: true
- name: Audit State Machine Unwired Guards (死守卫 / 假保护防御)
run: node --import tsx scripts/audit-state-machine-unwired-guards.ts
continue-on-error: true
- name: Audit Migration Topology (影子迁移防御)
run: node --import tsx scripts/audit-migration-topology.ts
continue-on-error: true
- name: Audit API Test Fixed IDs (并行化降债棘轮 / write-pk)
run: pnpm -C backend run audit:api-test-fixed-ids
continue-on-error: true
- name: 30d Evidence - Launch Smoke Scope
run: pnpm run audit:launch-smoke-scope
continue-on-error: true
- name: 30d Evidence - Rollout Scope Freeze
run: pnpm run audit:rollout-scope-freeze
continue-on-error: true
- name: 30d Evidence - Production Foundation
run: pnpm run audit:production-foundation-evidence
continue-on-error: true
- name: 30d Evidence - RLS Staging Canary Plan
run: pnpm run audit:rls-staging-canary
continue-on-error: true
- name: 30d Evidence - Customer Signoff Status
run: node --import tsx scripts/harness/customer-signoff-status.ts
continue-on-error: true
- name: 30d Evidence - Production Gate Projection
run: node --import tsx scripts/production-release-gate.ts --no-fail
continue-on-error: true
- name: 30d Evidence - Gate Integrity
run: pnpm run audit:production-release-gate-integrity
continue-on-error: true
- name: Harness Report 聚合
run: pnpm harness report --save
continue-on-error: true
- name: 30d Evidence - Harness Meta Tests
run: pnpm run harness:test
- name: 30d Evidence - War Plan Markdown
run: node --import tsx scripts/governance-30d-war-plan.ts
- if: always()
name: Upload audit reports
uses: https://gitea.com/actions/upload-artifact@v3
with:
name: governance-audit-reports
path: |
reports/prisma-zod-contract-audit.latest.json
reports/formrules-zod-audit.latest.json
reports/response-columns-audit.latest.json
reports/field-payload-audit.latest.json
reports/enum-consistency-audit.latest.json
reports/list-page-routes-audit.latest.json
reports/ai-assist-coverage.latest.json
reports/ai-assist-skill-binding.latest.json
reports/ai-assist-context-providers.latest.json
reports/coach-script-library.latest.json
reports/ai-decision-quality.latest.json
reports/event-publishing-audit.latest.json
reports/state-machine-integration-audit.latest.json
reports/harness-dashboard.latest.json
reports/module-grades.latest.json
reports/money-decimal-purity-audit.latest.json
reports/nested-transaction-audit.latest.json
reports/test-assertion-density-audit.latest.json
reports/api-test-coverage.latest.json
reports/api-test-fixed-ids-audit.latest.json
reports/consumer-test-authenticity-audit.latest.json
reports/consumer-idempotency-audit.latest.json
reports/state-machine-unwired-guards-audit.latest.json
reports/migration-topology-audit.latest.json
reports/customer-signoff-status.latest.json
reports/p0-customer-input-status.latest.json
reports/rollout-scope-freeze.latest.json
reports/rollout-scope-freeze.latest.md
reports/production-foundation-evidence.latest.json
reports/production-foundation-evidence.latest.md
reports/launch-smoke-scope.latest.json
reports/launch-smoke-scope.latest.md
reports/rls-staging-canary.latest.json
reports/rls-staging-canary.latest.md
reports/production-release-gate.latest.json
reports/production-release-gate.latest.md
reports/production-release-actions.latest.json
reports/production-release-actions.latest.md
reports/production-release-gate-integrity.latest.json
reports/production-release-gate-integrity.latest.md
reports/governance-30d-war-plan.latest.md
retention-days: "14"
- if: always()
name: 输出 governance summary
run: node --import tsx scripts/ci-governance-summary.ts --title "Governance Audit Summary" --include-rules
- name: 治理硬门禁 — 豁免感知 verdict(HARD)
run: node --import tsx scripts/harness/governance-gate.ts
- name: 文档对账 — CLAUDE.md GOVERNANCE-BASELINE ↔ reports 实测(HARD)
run: node --import tsx scripts/harness/baseline-reconcile.ts
- name: Harness Gate 综合 PR 验收(HARD)
run: pnpm harness gate
...
|
governance-audit
|
["lint-and-typecheck"]
|
["ubuntu-latest"]
|
27007
|
2
|
1780926753
|
1780928762
|
1780924423
|
1780928762
|
|
1
|
|
0
|
Edit
Delete
|
|
30868
|
23394
|
13
|
5
|
6c80c00976d1c5ac4aaa5f76d10cf1e7b4f59448
|
0
|
Analyze (java)
|
1
|
name: CodeQL Analysis
"on":
push:
name: CodeQL Analysis
"on":
push:
branches: [develop, master, main]
pull_request:
branches: [develop, master, main]
schedule:
# 每周一凌晨3点运行
- cron: '0 3 * * 1'
jobs:
analyze:
name: Analyze (java)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
cache: gradle
distribution: temurin
java-version: "17"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
- name: Grant Execute Permission
run: chmod +x ./gradlew
- name: Build
run: ./gradlew assembleDebug --stacktrace
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: /language:${{ matrix.language }}
timeout-minutes: "30"
strategy:
fail-fast: "false"
matrix:
language:
- java
permissions:
actions: read
contents: read
security-events: write
...
|
analyze
|
null
|
["ubuntu-latest"]
|
27008
|
2
|
1781492429
|
1781492519
|
1781492428
|
1781492519
|
|
0
|
|
0
|
Edit
Delete
|
|
16
|
15
|
2
|
2
|
061edb11a5fd660934c3b57491d585077b3805cf
|
0
|
deploy
|
0
|
name: Smart Deploy via Rsync Daemon
"on": name: Smart Deploy via Rsync Daemon
"on": [push]
jobs:
deploy:
name: deploy
runs-on: self-hosted
steps:
- name: Checkout code manually
run: |
# 调试输出
echo "GITEA_HOST: $GITEA_HOST"
echo "GITHUB_REPOSITORY: ${{ github.repository }}"
echo "GITHUB_SHA: ${{ github.sha }}"
if [ -z "$GITEA_HOST" ]; then
echo "❌ GITEA_HOST secret is missing!"
exit 1
fi
# 使用 github 上下文变量
REPO="${{ github.repository }}"
SHA="${{ github.sha }}"
if [ -z "$REPO" ] || [ -z "$SHA" ]; then
echo "❌ Missing GITHUB_REPOSITORY or GITHUB_SHA"
exit 1
fi
REPO_URL="https://${GITEA_TOKEN}@${GITEA_HOST}/${REPO}.git"
echo "Cloning from: ${REPO_URL//${GITEA_TOKEN}/***REDACTED***} (SHA: $SHA)"
git init
git remote add origin "$REPO_URL"
git fetch --depth=1 origin "$SHA"
git checkout "$SHA"
env:
GITEA_HOST: ${{ secrets.GITEAS_HOST }}
GITEA_TOKEN: ${{ secrets.GITEAS_TOKEN }}
- name: Prepare rsync password file
run: |
echo "$RSYNC_PASSWORD" > /tmp/rsync.pass
chmod 600 /tmp/rsync.pass
env:
RSYNC_PASSWORD: ${{ secrets.TEST_RSYNC_SECRETS }}
- name: Get commit message and decide sync mode
run: "COMMIT_MSG=$(git log -1 --pretty=%B | head -n1)\necho \"Commit message: $COMMIT_MSG\"\n\nRSYNC_TARGET=\"rsync://${RSYNC_USER}@${RSYNC_HOST}/${RSYNC_MODULE}/\"\n\nif [[ \"$COMMIT_MSG\" == *\"全量同步\"* ]] || [[ \"$COMMIT_MSG\" == *\"full sync\"* ]]; then\n echo \"\U0001F50D Full sync requested...\"\n rsync -avz --delete \\\n --exclude='.git' \\\n --exclude='.gitea' \\\n --exclude='node_modules/' \\\n --password-file=/tmp/rsync.pass \\\n ./ \\\n \"$RSYNC_TARGET\"\nelse\n echo \"\U0001F504 Incremental sync...\"\n\n if git rev-parse HEAD~1 >/dev/null 2>&1; then\n git diff --name-only HEAD~1 HEAD > /tmp/changed.txt\n else\n find . -type f -not -path './.git/*' -not -path './.gitea/*' | sed 's|^\\./||' > /tmp/changed.txt\n fi\n\n if [ -s /tmp/changed.txt ]; then\n echo \"Files to sync:\"\n cat /tmp/changed.txt\n \n rsync -avz --relative \\\n --files-from=/tmp/changed.txt \\\n --password-file=/tmp/rsync.pass \\\n ./ \\\n \"$RSYNC_TARGET\"\n else\n echo \"✅ No files changed.\"\n fi\nfi\n"
env:
RSYNC_HOST: ${{ secrets.TEST_RSYNC_HOST }}
RSYNC_USER: ${{ secrets.TEST_RSYNC_USER }}
RSYNC_MODULE: ftp
- if: always()
name: Clean up
run: rm -f /tmp/rsync.pass
...
|
deploy
|
null
|
["self-hosted"]
|
0
|
3
|
0
|
1770875534
|
1770874771
|
1770875534
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
17
|
16
|
2
|
2
|
062acdd73d520de0360ff9d9158e60f202a02578
|
0
|
deploy
|
0
|
name: Smart Deploy via Rsync Daemon
"on": name: Smart Deploy via Rsync Daemon
"on": [push]
jobs:
deploy:
name: deploy
runs-on: gitea.g-hi.com/zhangjunnan/gitea-runner:node20-rsync-v1
steps:
- name: Checkout code manually
run: |
# 调试输出
echo "GITEA_HOST: $GITEA_HOST"
echo "GITHUB_REPOSITORY: ${{ github.repository }}"
echo "GITHUB_SHA: ${{ github.sha }}"
if [ -z "$GITEA_HOST" ]; then
echo "❌ GITEA_HOST secret is missing!"
exit 1
fi
# 使用 github 上下文变量
REPO="${{ github.repository }}"
SHA="${{ github.sha }}"
if [ -z "$REPO" ] || [ -z "$SHA" ]; then
echo "❌ Missing GITHUB_REPOSITORY or GITHUB_SHA"
exit 1
fi
REPO_URL="https://${GITEA_TOKEN}@${GITEA_HOST}/${REPO}.git"
echo "Cloning from: ${REPO_URL//${GITEA_TOKEN}/***REDACTED***} (SHA: $SHA)"
git init
git remote add origin "$REPO_URL"
git fetch --depth=1 origin "$SHA"
git checkout "$SHA"
env:
GITEA_HOST: ${{ secrets.GITEAS_HOST }}
GITEA_TOKEN: ${{ secrets.GITEAS_TOKEN }}
- name: Prepare rsync password file
run: |
echo "$RSYNC_PASSWORD" > /tmp/rsync.pass
chmod 600 /tmp/rsync.pass
env:
RSYNC_PASSWORD: ${{ secrets.TEST_RSYNC_SECRETS }}
- name: Get commit message and decide sync mode
run: "COMMIT_MSG=$(git log -1 --pretty=%B | head -n1)\necho \"Commit message: $COMMIT_MSG\"\n\nRSYNC_TARGET=\"rsync://${RSYNC_USER}@${RSYNC_HOST}/${RSYNC_MODULE}/\"\n\nif [[ \"$COMMIT_MSG\" == *\"全量同步\"* ]] || [[ \"$COMMIT_MSG\" == *\"full sync\"* ]]; then\n echo \"\U0001F50D Full sync requested...\"\n rsync -avz --delete \\\n --exclude='.git' \\\n --exclude='.gitea' \\\n --exclude='node_modules/' \\\n --password-file=/tmp/rsync.pass \\\n ./ \\\n \"$RSYNC_TARGET\"\nelse\n echo \"\U0001F504 Incremental sync...\"\n\n if git rev-parse HEAD~1 >/dev/null 2>&1; then\n git diff --name-only HEAD~1 HEAD > /tmp/changed.txt\n else\n find . -type f -not -path './.git/*' -not -path './.gitea/*' | sed 's|^\\./||' > /tmp/changed.txt\n fi\n\n if [ -s /tmp/changed.txt ]; then\n echo \"Files to sync:\"\n cat /tmp/changed.txt\n \n rsync -avz --relative \\\n --files-from=/tmp/changed.txt \\\n --password-file=/tmp/rsync.pass \\\n ./ \\\n \"$RSYNC_TARGET\"\n else\n echo \"✅ No files changed.\"\n fi\nfi\n"
env:
RSYNC_HOST: ${{ secrets.TEST_RSYNC_HOST }}
RSYNC_USER: ${{ secrets.TEST_RSYNC_USER }}
RSYNC_MODULE: ftp
- if: always()
name: Clean up
run: rm -f /tmp/rsync.pass
...
|
deploy
|
null
|
["gitea.g-hi.com/zhangjunnan/gitea-runner:node ["gitea.g-hi.com/zhangjunnan/gitea-runner:node20-rsync-v1"]...
|
0
|
3
|
0
|
1770877321
|
1770877295
|
1770877321
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
18
|
17
|
2
|
2
|
5bb99418afc48f8e77d3cdb4edd9fa1390476c57
|
0
|
deploy
|
0
|
name: Smart Deploy via Rsync Daemon
"on": name: Smart Deploy via Rsync Daemon
"on": [push]
jobs:
deploy:
name: deploy
runs-on: gitea.g-hi.com/zhangjunnan/gitea-runner:node20-rsync-v1
steps:
- name: Checkout code manually
run: |
# 调试输出
echo "GITEA_HOST: $GITEA_HOST"
echo "GITHUB_REPOSITORY: ${{ github.repository }}"
echo "GITHUB_SHA: ${{ github.sha }}"
if [ -z "$GITEA_HOST" ]; then
echo "❌ GITEA_HOST secret is missing!"
exit 1
fi
# 使用 github 上下文变量
REPO="${{ github.repository }}"
SHA="${{ github.sha }}"
if [ -z "$REPO" ] || [ -z "$SHA" ]; then
echo "❌ Missing GITHUB_REPOSITORY or GITHUB_SHA"
exit 1
fi
REPO_URL="https://${GITEA_TOKEN}@${GITEA_HOST}/${REPO}.git"
echo "Cloning from: ${REPO_URL//${GITEA_TOKEN}/***REDACTED***} (SHA: $SHA)"
git init
git remote add origin "$REPO_URL"
git fetch --depth=1 origin "$SHA"
git checkout "$SHA"
env:
GITEA_HOST: ${{ secrets.GITEAS_HOST }}
GITEA_TOKEN: ${{ secrets.GITEAS_TOKEN }}
- name: Prepare rsync password file
run: |
echo "$RSYNC_PASSWORD" > /tmp/rsync.pass
chmod 600 /tmp/rsync.pass
env:
RSYNC_PASSWORD: ${{ secrets.TEST_RSYNC_SECRETS }}
- name: Get commit message and decide sync mode
run: "COMMIT_MSG=$(git log -1 --pretty=%B | head -n1)\necho \"Commit message: $COMMIT_MSG\"\n\nRSYNC_TARGET=\"rsync://${RSYNC_USER}@${RSYNC_HOST}/${RSYNC_MODULE}/\"\n\nif [[ \"$COMMIT_MSG\" == *\"全量同步\"* ]] || [[ \"$COMMIT_MSG\" == *\"full sync\"* ]]; then\n echo \"\U0001F50D Full sync requested...\"\n rsync -avz --delete \\\n --exclude='.git' \\\n --exclude='.gitea' \\\n --exclude='node_modules/' \\\n --password-file=/tmp/rsync.pass \\\n ./ \\\n \"$RSYNC_TARGET\"\nelse\n echo \"\U0001F504 Incremental sync...\"\n\n if git rev-parse HEAD~1 >/dev/null 2>&1; then\n git diff --name-only HEAD~1 HEAD > /tmp/changed.txt\n else\n find . -type f -not -path './.git/*' -not -path './.gitea/*' | sed 's|^\\./||' > /tmp/changed.txt\n fi\n\n if [ -s /tmp/changed.txt ]; then\n echo \"Files to sync:\"\n cat /tmp/changed.txt\n \n rsync -avz --relative \\\n --files-from=/tmp/changed.txt \\\n --password-file=/tmp/rsync.pass \\\n ./ \\\n \"$RSYNC_TARGET\"\n else\n echo \"✅ No files changed.\"\n fi\nfi\n"
env:
RSYNC_HOST: ${{ secrets.TEST_RSYNC_HOST }}
RSYNC_USER: ${{ secrets.TEST_RSYNC_USER }}
RSYNC_MODULE: ftp
- if: always()
name: Clean up
run: rm -f /tmp/rsync.pass
...
|
deploy
|
null
|
["gitea.g-hi.com/zhangjunnan/gitea-runner:node ["gitea.g-hi.com/zhangjunnan/gitea-runner:node20-rsync-v1"]...
|
0
|
3
|
0
|
1770877939
|
1770877350
|
1770877939
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
19
|
18
|
2
|
2
|
fbac0054c597227db514fa1c6581f5e9002a4c84
|
0
|
deploy
|
0
|
name: Smart Deploy via Rsync Daemon
"on": name: Smart Deploy via Rsync Daemon
"on": [push]
jobs:
deploy:
name: deploy
runs-on: gitea.g-hi.com/zhangjunnan/gitea-runner:node20-rsync-v1
steps:
- name: Checkout code manually
run: |
# 调试输出
echo "GITEA_HOST: $GITEA_HOST"
echo "GITHUB_REPOSITORY: ${{ github.repository }}"
echo "GITHUB_SHA: ${{ github.sha }}"
if [ -z "$GITEA_HOST" ]; then
echo "❌ GITEA_HOST secret is missing!"
exit 1
fi
# 使用 github 上下文变量
REPO="${{ github.repository }}"
SHA="${{ github.sha }}"
if [ -z "$REPO" ] || [ -z "$SHA" ]; then
echo "❌ Missing GITHUB_REPOSITORY or GITHUB_SHA"
exit 1
fi
REPO_URL="https://${GITEA_TOKEN}@${GITEA_HOST}/${REPO}.git"
echo "Cloning from: ${REPO_URL//${GITEA_TOKEN}/***REDACTED***} (SHA: $SHA)"
git init
git remote add origin "$REPO_URL"
git fetch --depth=1 origin "$SHA"
git checkout "$SHA"
env:
GITEA_HOST: ${{ secrets.GITEAS_HOST }}
GITEA_TOKEN: ${{ secrets.GITEAS_TOKEN }}
- name: Prepare rsync password file
run: |
echo "$RSYNC_PASSWORD" > /tmp/rsync.pass
chmod 600 /tmp/rsync.pass
env:
RSYNC_PASSWORD: ${{ secrets.TEST_RSYNC_SECRETS }}
- name: Get commit message and decide sync mode
run: "COMMIT_MSG=$(git log -1 --pretty=%B | head -n1)\necho \"Commit message: $COMMIT_MSG\"\n\nRSYNC_TARGET=\"rsync://${RSYNC_USER}@${RSYNC_HOST}/${RSYNC_MODULE}/\"\n\nif [[ \"$COMMIT_MSG\" == *\"全量同步\"* ]] || [[ \"$COMMIT_MSG\" == *\"full sync\"* ]]; then\n echo \"\U0001F50D Full sync requested...\"\n rsync -avz --delete \\\n --exclude='.git' \\\n --exclude='.gitea' \\\n --exclude='node_modules/' \\\n --password-file=/tmp/rsync.pass \\\n ./ \\\n \"$RSYNC_TARGET\"\nelse\n echo \"\U0001F504 Incremental sync...\"\n\n if git rev-parse HEAD~1 >/dev/null 2>&1; then\n git diff --name-only HEAD~1 HEAD > /tmp/changed.txt\n else\n find . -type f -not -path './.git/*' -not -path './.gitea/*' | sed 's|^\\./||' > /tmp/changed.txt\n fi\n\n if [ -s /tmp/changed.txt ]; then\n echo \"Files to sync:\"\n cat /tmp/changed.txt\n \n rsync -avz --relative \\\n --files-from=/tmp/changed.txt \\\n --password-file=/tmp/rsync.pass \\\n ./ \\\n \"$RSYNC_TARGET\"\n else\n echo \"✅ No files changed.\"\n fi\nfi\n"
env:
RSYNC_HOST: ${{ secrets.TEST_RSYNC_HOST }}
RSYNC_USER: ${{ secrets.TEST_RSYNC_USER }}
RSYNC_MODULE: ftp
- if: always()
name: Clean up
run: rm -f /tmp/rsync.pass
...
|
deploy
|
null
|
["gitea.g-hi.com/zhangjunnan/gitea-runner:node ["gitea.g-hi.com/zhangjunnan/gitea-runner:node20-rsync-v1"]...
|
0
|
3
|
0
|
1770878173
|
1770878076
|
1770878173
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
20
|
19
|
2
|
2
|
b277cb95b0e9e11aded5a72555e5bfe6066bd7b5
|
0
|
deploy
|
0
|
name: Smart Deploy via Rsync Daemon
"on": name: Smart Deploy via Rsync Daemon
"on": [push]
jobs:
deploy:
name: deploy
runs-on: gitea.g-hi.com/zhangjunnan/gitea-runner:node20-rsync-v1
steps:
- name: Checkout code manually
run: |
# 调试输出
echo "GITEA_HOST: $GITEA_HOST"
echo "GITHUB_REPOSITORY: ${{ github.repository }}"
echo "GITHUB_SHA: ${{ github.sha }}"
if [ -z "$GITEA_HOST" ]; then
echo "❌ GITEA_HOST secret is missing!"
exit 1
fi
# 使用 github 上下文变量
REPO="${{ github.repository }}"
SHA="${{ github.sha }}"
if [ -z "$REPO" ] || [ -z "$SHA" ]; then
echo "❌ Missing GITHUB_REPOSITORY or GITHUB_SHA"
exit 1
fi
REPO_URL="https://${GITEA_TOKEN}@${GITEA_HOST}/${REPO}.git"
echo "Cloning from: ${REPO_URL//${GITEA_TOKEN}/***REDACTED***} (SHA: $SHA)"
git init
git remote add origin "$REPO_URL"
git fetch --depth=1 origin "$SHA"
git checkout "$SHA"
env:
GITEA_HOST: ${{ secrets.GITEAS_HOST }}
GITEA_TOKEN: ${{ secrets.GITEAS_TOKEN }}
- name: Prepare rsync password file
run: |
echo "$RSYNC_PASSWORD" > /tmp/rsync.pass
chmod 600 /tmp/rsync.pass
env:
RSYNC_PASSWORD: ${{ secrets.TEST_RSYNC_SECRETS }}
- name: Get commit message and decide sync mode
run: "COMMIT_MSG=$(git log -1 --pretty=%B | head -n1)\necho \"Commit message: $COMMIT_MSG\"\n\nRSYNC_TARGET=\"rsync://${RSYNC_USER}@${RSYNC_HOST}/${RSYNC_MODULE}/\"\n\nif [[ \"$COMMIT_MSG\" == *\"全量同步\"* ]] || [[ \"$COMMIT_MSG\" == *\"full sync\"* ]]; then\n echo \"\U0001F50D Full sync requested...\"\n rsync -avz --delete \\\n --exclude='.git' \\\n --exclude='.gitea' \\\n --exclude='node_modules/' \\\n --password-file=/tmp/rsync.pass \\\n ./ \\\n \"$RSYNC_TARGET\"\nelse\n echo \"\U0001F504 Incremental sync...\"\n\n if git rev-parse HEAD~1 >/dev/null 2>&1; then\n git diff --name-only HEAD~1 HEAD > /tmp/changed.txt\n else\n find . -type f -not -path './.git/*' -not -path './.gitea/*' | sed 's|^\\./||' > /tmp/changed.txt\n fi\n\n if [ -s /tmp/changed.txt ]; then\n echo \"Files to sync:\"\n cat /tmp/changed.txt\n \n rsync -avz --relative \\\n --files-from=/tmp/changed.txt \\\n --password-file=/tmp/rsync.pass \\\n ./ \\\n \"$RSYNC_TARGET\"\n else\n echo \"✅ No files changed.\"\n fi\nfi\n"
env:
RSYNC_HOST: ${{ secrets.TEST_RSYNC_HOST }}
RSYNC_USER: ${{ secrets.TEST_RSYNC_USER }}
RSYNC_MODULE: ftp
- if: always()
name: Clean up
run: rm -f /tmp/rsync.pass
...
|
deploy
|
null
|
["gitea.g-hi.com/zhangjunnan/gitea-runner:node ["gitea.g-hi.com/zhangjunnan/gitea-runner:node20-rsync-v1"]...
|
0
|
3
|
0
|
1770878314
|
1770878195
|
1770878314
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
21
|
20
|
2
|
2
|
22ffb09cf279f85db485e386b24c7d3a1cdda4e6
|
0
|
deploy
|
0
|
name: Smart Deploy via Rsync Daemon
"on": name: Smart Deploy via Rsync Daemon
"on": [push]
jobs:
deploy:
name: deploy
runs-on: docker://gitea.g-hi.com/zhangjunnan/gitea-runner:node20-rsync-v1
steps:
- name: Checkout code manually
run: |
# 调试输出
echo "GITEA_HOST: $GITEA_HOST"
echo "GITHUB_REPOSITORY: ${{ github.repository }}"
echo "GITHUB_SHA: ${{ github.sha }}"
if [ -z "$GITEA_HOST" ]; then
echo "❌ GITEA_HOST secret is missing!"
exit 1
fi
# 使用 github 上下文变量
REPO="${{ github.repository }}"
SHA="${{ github.sha }}"
if [ -z "$REPO" ] || [ -z "$SHA" ]; then
echo "❌ Missing GITHUB_REPOSITORY or GITHUB_SHA"
exit 1
fi
REPO_URL="https://${GITEA_TOKEN}@${GITEA_HOST}/${REPO}.git"
echo "Cloning from: ${REPO_URL//${GITEA_TOKEN}/***REDACTED***} (SHA: $SHA)"
git init
git remote add origin "$REPO_URL"
git fetch --depth=1 origin "$SHA"
git checkout "$SHA"
env:
GITEA_HOST: ${{ secrets.GITEAS_HOST }}
GITEA_TOKEN: ${{ secrets.GITEAS_TOKEN }}
- name: Prepare rsync password file
run: |
echo "$RSYNC_PASSWORD" > /tmp/rsync.pass
chmod 600 /tmp/rsync.pass
env:
RSYNC_PASSWORD: ${{ secrets.TEST_RSYNC_SECRETS }}
- name: Get commit message and decide sync mode
run: "COMMIT_MSG=$(git log -1 --pretty=%B | head -n1)\necho \"Commit message: $COMMIT_MSG\"\n\nRSYNC_TARGET=\"rsync://${RSYNC_USER}@${RSYNC_HOST}/${RSYNC_MODULE}/\"\n\nif [[ \"$COMMIT_MSG\" == *\"全量同步\"* ]] || [[ \"$COMMIT_MSG\" == *\"full sync\"* ]]; then\n echo \"\U0001F50D Full sync requested...\"\n rsync -avz --delete \\\n --exclude='.git' \\\n --exclude='.gitea' \\\n --exclude='node_modules/' \\\n --password-file=/tmp/rsync.pass \\\n ./ \\\n \"$RSYNC_TARGET\"\nelse\n echo \"\U0001F504 Incremental sync...\"\n\n if git rev-parse HEAD~1 >/dev/null 2>&1; then\n git diff --name-only HEAD~1 HEAD > /tmp/changed.txt\n else\n find . -type f -not -path './.git/*' -not -path './.gitea/*' | sed 's|^\\./||' > /tmp/changed.txt\n fi\n\n if [ -s /tmp/changed.txt ]; then\n echo \"Files to sync:\"\n cat /tmp/changed.txt\n \n rsync -avz --relative \\\n --files-from=/tmp/changed.txt \\\n --password-file=/tmp/rsync.pass \\\n ./ \\\n \"$RSYNC_TARGET\"\n else\n echo \"✅ No files changed.\"\n fi\nfi\n"
env:
RSYNC_HOST: ${{ secrets.TEST_RSYNC_HOST }}
RSYNC_USER: ${{ secrets.TEST_RSYNC_USER }}
RSYNC_MODULE: ftp
- if: always()
name: Clean up
run: rm -f /tmp/rsync.pass
...
|
deploy
|
null
|
["docker://gitea.g-hi.com/zhangjunnan/gitea-ru ["docker://gitea.g-hi.com/zhangjunnan/gitea-runner:node20-rsync-v1"]...
|
0
|
3
|
0
|
1770878361
|
1770878332
|
1770878361
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
24
|
23
|
2
|
2
|
2ac24ff0484bc4a60c5bfed9495a83a4e337f27b
|
0
|
deploy
|
0
|
name: Smart Deploy via Rsync Daemon
"on": name: Smart Deploy via Rsync Daemon
"on": [push]
jobs:
deploy:
name: deploy
runs-on: ubuntu-latest
steps:
- name: Checkout code manually
run: |
# 调试输出
echo "GITEA_HOST: $GITEA_HOST"
echo "GITHUB_REPOSITORY: ${{ github.repository }}"
echo "GITHUB_SHA: ${{ github.sha }}"
if [ -z "$GITEA_HOST" ]; then
echo "❌ GITEA_HOST secret is missing!"
exit 1
fi
# 使用 github 上下文变量
REPO="${{ github.repository }}"
SHA="${{ github.sha }}"
if [ -z "$REPO" ] || [ -z "$SHA" ]; then
echo "❌ Missing GITHUB_REPOSITORY or GITHUB_SHA"
exit 1
fi
REPO_URL="https://${GITEA_TOKEN}@${GITEA_HOST}/${REPO}.git"
echo "Cloning from: ${REPO_URL//${GITEA_TOKEN}/***REDACTED***} (SHA: $SHA)"
git init
git remote add origin "$REPO_URL"
git fetch --depth=1 origin "$SHA"
git checkout "$SHA"
env:
GITEA_HOST: ${{ secrets.GITEAS_HOST }}
GITEA_TOKEN: ${{ secrets.GITEAS_TOKEN }}
- name: Prepare rsync password file
run: |
echo "$RSYNC_PASSWORD" > /tmp/rsync.pass
chmod 600 /tmp/rsync.pass
env:
RSYNC_PASSWORD: ${{ secrets.TEST_RSYNC_SECRETS }}
- name: Get commit message and decide sync mode
run: "COMMIT_MSG=$(git log -1 --pretty=%B | head -n1)\necho \"Commit message: $COMMIT_MSG\"\n\nRSYNC_TARGET=\"rsync://${RSYNC_USER}@${RSYNC_HOST}/${RSYNC_MODULE}/\"\n\nif [[ \"$COMMIT_MSG\" == *\"全量同步\"* ]] || [[ \"$COMMIT_MSG\" == *\"full sync\"* ]]; then\n echo \"\U0001F50D Full sync requested...\"\n /usr/bin/rsync -avz --delete \\\n --exclude='.git' \\\n --exclude='.gitea' \\\n --exclude='node_modules/' \\\n --password-file=/tmp/rsync.pass \\\n ./ \\\n \"$RSYNC_TARGET\"\nelse\n echo \"\U0001F504 Incremental sync...\"\n\n if git rev-parse HEAD~1 >/dev/null 2>&1; then\n git diff --name-only HEAD~1 HEAD > /tmp/changed.txt\n else\n find . -type f -not -path './.git/*' -not -path './.gitea/*' | sed 's|^\\./||' > /tmp/changed.txt\n fi\n\n if [ -s /tmp/changed.txt ]; then\n echo \"Files to sync:\"\n cat /tmp/changed.txt\n \n /usr/bin/rsync -avz --relative \\\n --files-from=/tmp/changed.txt \\\n --password-file=/tmp/rsync.pass \\\n ./ \\\n \"$RSYNC_TARGET\"\n else\n echo \"✅ No files changed.\"\n fi\nfi\n"
env:
RSYNC_HOST: ${{ secrets.TEST_RSYNC_HOST }}
RSYNC_USER: ${{ secrets.TEST_RSYNC_USER }}
RSYNC_MODULE: ftp
- if: always()
name: Clean up
run: rm -f /tmp/rsync.pass
...
|
deploy
|
null
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1770884630
|
1770882563
|
1770884630
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
38
|
37
|
2
|
2
|
359a23bb2b3c088576051d47f237505eaa12d9e9
|
0
|
deploy
|
1
|
name: Smart Deploy via Rsync Daemon
"on": name: Smart Deploy via Rsync Daemon
"on": [push]
jobs:
deploy:
name: deploy
runs-on: ubuntu-latest
steps:
- name: Checkout code manually
run: |
# 调试输出
echo "GITEA_HOST: $GITEA_HOST"
echo "GITHUB_REPOSITORY: ${{ github.repository }}"
echo "GITHUB_SHA: ${{ github.sha }}"
if [ -z "$GITEA_HOST" ]; then
echo "❌ GITEA_HOST secret is missing!"
exit 1
fi
# 使用 github 上下文变量
REPO="${{ github.repository }}"
SHA="${{ github.sha }}"
if [ -z "$REPO" ] || [ -z "$SHA" ]; then
echo "❌ Missing GITHUB_REPOSITORY or GITHUB_SHA"
exit 1
fi
REPO_URL="https://${GITEA_TOKEN}@${GITEA_HOST}/${REPO}.git"
echo "Cloning from: ${REPO_URL//${GITEA_TOKEN}/***REDACTED***} (SHA: $SHA)"
git init
git remote add origin "$REPO_URL"
git fetch --depth=1 origin "$SHA"
git checkout "$SHA"
env:
GITEA_HOST: ${{ secrets.GITEAS_HOST }}
GITEA_TOKEN: ${{ secrets.GITEAS_TOKEN }}
- name: Prepare rsync password file (HARDCODED for test)
run: |
echo "m9QNiLJ8LIqBozXwmsoKdNXa23xia34R" > /tmp/rsync.pass
chmod 600 /tmp/rsync.pass
echo "✅ /tmp/rsync.pass created with password 'm9QNiLJ8LIqBozXwmsoKdNXa23xia34R'"
- name: Get commit message and decide sync mode
run: "COMMIT_MSG=$(git log -1 --pretty=%B | head -n1)\necho \"Commit message: $COMMIT_MSG\"\n\nRSYNC_TARGET=\"rsync://${RSYNC_USER}@${RSYNC_HOST}/${RSYNC_MODULE}/\"\n\nif [[ \"$COMMIT_MSG\" == *\"全量同步\"* ]] || [[ \"$COMMIT_MSG\" == *\"full sync\"* ]]; then\n echo \"\U0001F50D Full sync requested...\"\n /usr/bin/rsync -avz --no-owner --no-group --delete \\\n --exclude='.git' \\\n --exclude='.gitea' \\\n --exclude='node_modules/' \\\n --password-file=/tmp/rsync.pass \\\n . \\\n \"$RSYNC_TARGET\"\nelse\n echo \"\U0001F504 Incremental sync...\"\n\n if git rev-parse HEAD~1 >/dev/null 2>&1; then\n git diff --name-only HEAD~1 HEAD > /tmp/changed.txt\n else\n find . -type f -not -path './.git/*' -not -path './.gitea/*' | sed 's|^\\./||' > /tmp/changed.txt\n fi\n\n if [ -s /tmp/changed.txt ]; then\n echo \"Files to sync:\"\n cat /tmp/changed.txt\n echo \"Total changed files: $(wc -l < /tmp/changed.txt)\"\n\n # ✅ 关键修复:去掉 --relative\n /usr/bin/rsync -avz --no-owner --no-group \\\n --files-from=/tmp/changed.txt \\\n . \\\n \"$RSYNC_TARGET\"\n else\n echo \"✅ No files changed.\"\n fi\nfi\n"
env:
RSYNC_HOST: "172.17.70.241"
RSYNC_USER: "ahead_rsync_user"
RSYNC_MODULE: "ftp"
- if: always()
name: Clean up
run: rm -f /tmp/rsync.pass
...
|
deploy
|
null
|
["ubuntu-latest"]
|
30
|
3
|
1770890490
|
1770890599
|
1770890489
|
1770890599
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
39
|
38
|
2
|
2
|
8b9043cb7c726e4e59948720bb4009d9c10c8041
|
0
|
deploy
|
1
|
name: Smart Deploy via Rsync Daemon
"on": name: Smart Deploy via Rsync Daemon
"on": [push]
jobs:
deploy:
name: deploy
runs-on: ubuntu-latest
steps:
- name: Checkout code manually
run: |
# 调试输出
echo "GITEA_HOST: $GITEA_HOST"
echo "GITHUB_REPOSITORY: ${{ github.repository }}"
echo "GITHUB_SHA: ${{ github.sha }}"
if [ -z "$GITEA_HOST" ]; then
echo "❌ GITEA_HOST secret is missing!"
exit 1
fi
# 使用 github 上下文变量
REPO="${{ github.repository }}"
SHA="${{ github.sha }}"
if [ -z "$REPO" ] || [ -z "$SHA" ]; then
echo "❌ Missing GITHUB_REPOSITORY or GITHUB_SHA"
exit 1
fi
REPO_URL="https://${GITEA_TOKEN}@${GITEA_HOST}/${REPO}.git"
echo "Cloning from: ${REPO_URL//${GITEA_TOKEN}/***REDACTED***} (SHA: $SHA)"
git init
git remote add origin "$REPO_URL"
git fetch --depth=1 origin "$SHA"
git checkout "$SHA"
env:
GITEA_HOST: ${{ secrets.GITEAS_HOST }}
GITEA_TOKEN: ${{ secrets.GITEAS_TOKEN }}
- name: Prepare rsync password file (HARDCODED for test)
run: |
echo "m9QNiLJ8LIqBozXwmsoKdNXa23xia34R" > /tmp/rsync.pass
chmod 600 /tmp/rsync.pass
echo "✅ /tmp/rsync.pass created with password 'm9QNiLJ8LIqBozXwmsoKdNXa23xia34R'"
- name: Get commit message and decide sync mode
run: "COMMIT_MSG=$(git log -1 --pretty=%B | head -n1)\necho \"Commit message: $COMMIT_MSG\"\n\nRSYNC_TARGET=\"rsync://${RSYNC_USER}@${RSYNC_HOST}/${RSYNC_MODULE}/\"\n\nif [[ \"$COMMIT_MSG\" == *\"全量同步\"* ]] || [[ \"$COMMIT_MSG\" == *\"full sync\"* ]]; then\n echo \"\U0001F50D Full sync requested...\"\n /usr/bin/rsync -avz --no-owner --no-group --delete \\\n --exclude='.git' \\\n --exclude='.gitea' \\\n --exclude='node_modules/' \\\n --password-file=/tmp/rsync.pass \\\n . \\\n \"$RSYNC_TARGET\"\nelse\n echo \"\U0001F504 Incremental sync...\"\n\n if git rev-parse HEAD~1 >/dev/null 2>&1; then\n git diff --name-only HEAD~1 HEAD > /tmp/changed.txt\n else\n find . -type f -not -path './.git/*' -not -path './.gitea/*' | sed 's|^\\./||' > /tmp/changed.txt\n fi\n\n if [ -s /tmp/changed.txt ]; then\n echo \"Files to sync:\"\n cat /tmp/changed.txt\n echo \"Total changed files: $(wc -l < /tmp/changed.txt)\"\n\n /usr/bin/rsync -avz --no-owner --no-group \\\n --files-from=/tmp/changed.txt \\\n . \\\n \"$RSYNC_TARGET\"\n else\n echo \"✅ No files changed.\"\n fi\nfi\n"
env:
RSYNC_HOST: "172.17.70.241"
RSYNC_USER: "ahead_rsync_user"
RSYNC_MODULE: "ftp"
- if: always()
name: Clean up
run: rm -f /tmp/rsync.pass
...
|
deploy
|
null
|
["ubuntu-latest"]
|
31
|
3
|
1770890621
|
1770890726
|
1770890620
|
1770890726
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
41
|
40
|
6
|
5
|
d169207d2a046f90cf861f8e805b45d3855fddc3
|
0
|
检测代码变更
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
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/**'
mobile:
- 'mobile/**'
- 'shared/**'
shared:
- 'shared/**'
workflows:
- '.github/workflows/**'
outputs:
backend: ${{ steps.filter.outputs.backend }}
frontend: ${{ steps.filter.outputs.frontend }}
mobile: ${{ steps.filter.outputs.mobile }}
shared: ${{ steps.filter.outputs.shared }}
workflows: ${{ steps.filter.outputs.workflows }}
...
|
detect-changes
|
null
|
["ubuntu-latest"]
|
33
|
3
|
1771862353
|
1771862367
|
1771862352
|
1771862367
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
42
|
40
|
6
|
5
|
d169207d2a046f90cf861f8e805b45d3855fddc3
|
0
|
安装依赖
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
setup:
name: 安装依赖
runs-on: ubuntu-latest
steps:
- name: 检出代码
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: deps-${{ runner.os }}-${{ 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"]
|
34
|
3
|
1771862354
|
1771862367
|
1771862352
|
1771862367
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
43
|
40
|
6
|
5
|
d169207d2a046f90cf861f8e805b45d3855fddc3
|
0
|
共享包检查
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
shared-check:
name: 共享包检查
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.shared == 'true'
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:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: TypeScript 类型检查
run: pnpm --filter @juhi/shared run build
- name: 验证导出
run: |
cd shared
node -e "import('./dist/index.js').then(m => console.log('✅ 共享包导出验证通过'))"
...
|
shared-check
|
["setup","detect-changes"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862367
|
1771862352
|
1771862367
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
44
|
40
|
6
|
5
|
d169207d2a046f90cf861f8e805b45d3855fddc3
|
0
|
后端代码检查
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
backend-lint:
name: 后端代码检查
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.backend == 'true'
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:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: ESLint 检查
run: pnpm --filter juhi-api run lint
- name: TypeScript 类型检查
run: pnpm --filter juhi-api run type-check
...
|
backend-lint
|
["setup","detect-changes"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862367
|
1771862352
|
1771862367
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
45
|
40
|
6
|
5
|
d169207d2a046f90cf861f8e805b45d3855fddc3
|
0
|
后端单元测试
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
backend-test:
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:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 运行单元测试
run: pnpm --filter juhi-api run test:ci
env:
DATABASE_URL: postgresql://test:test@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
JWT_SECRET: test-secret-key
NODE_ENV: test
- name: 上传覆盖率报告
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: "false"
files: backend/coverage/lcov.info
flags: backend
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: juhi_test
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-alpine
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
...
|
backend-test
|
["backend-lint"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862367
|
1771862352
|
1771862367
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
46
|
40
|
6
|
5
|
d169207d2a046f90cf861f8e805b45d3855fddc3
|
0
|
后端构建检查
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
backend-build:
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:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 构建
run: pnpm --filter juhi-api run build
- name: 验证构建产物
run: |
if [ ! -d "backend/dist" ]; then
echo "❌ 构建产物不存在"
exit 1
fi
echo "✅ 后端构建验证通过"
...
|
backend-build
|
["backend-lint"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862367
|
1771862352
|
1771862367
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
47
|
40
|
6
|
5
|
d169207d2a046f90cf861f8e805b45d3855fddc3
|
0
|
前端代码检查
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
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
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: ESLint 检查
run: pnpm --filter juhi-frontend run lint
- name: TypeScript 类型检查
run: pnpm --filter juhi-frontend run type-check
...
|
frontend-lint
|
["setup","detect-changes"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862367
|
1771862352
|
1771862367
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
48
|
40
|
6
|
5
|
d169207d2a046f90cf861f8e805b45d3855fddc3
|
0
|
前端构建检查
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
frontend-build:
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:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: 构建
run: pnpm --filter juhi-frontend run build
- name: 验证构建产物
run: |
if [ ! -d "frontend/dist" ]; then
echo "❌ 构建产物不存在"
exit 1
fi
echo "✅ 前端构建验证通过"
- name: 上传构建产物
uses: actions/upload-artifact@v4
with:
name: frontend-dist
path: frontend/dist
retention-days: "7"
...
|
frontend-build
|
["frontend-lint"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862367
|
1771862352
|
1771862367
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
49
|
40
|
6
|
5
|
d169207d2a046f90cf861f8e805b45d3855fddc3
|
0
|
移动端检查
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
mobile-check:
name: 移动端检查
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.mobile == 'true'
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:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: ESLint 检查
run: pnpm --filter juhi-mobile run lint || true
- name: TypeScript 类型检查
run: pnpm --filter juhi-mobile run type-check || true
...
|
mobile-check
|
["setup","detect-changes"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862367
|
1771862352
|
1771862367
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
50
|
40
|
6
|
5
|
d169207d2a046f90cf861f8e805b45d3855fddc3
|
0
|
多租户安全审计
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
security-audit:
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:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 运行多租户安全审计
run: pnpm --filter juhi-api run audit:tenant
continue-on-error: true
...
|
security-audit
|
["backend-lint"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862367
|
1771862352
|
1771862367
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
51
|
40
|
6
|
5
|
d169207d2a046f90cf861f8e805b45d3855fddc3
|
0
|
依赖安全审计
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
dependency-audit:
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:
node-version: ${{ env.NODE_VERSION }}
- name: pnpm 依赖审计
run: pnpm audit --audit-level high || true
...
|
dependency-audit
|
["setup"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862367
|
1771862352
|
1771862367
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
52
|
40
|
6
|
5
|
d169207d2a046f90cf861f8e805b45d3855fddc3
|
0
|
Docker 镜像构建
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
docker-build:
name: Docker 镜像构建
runs-on: ubuntu-latest
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')
steps:
- uses: actions/checkout@v4
- name: 设置 Docker Buildx
uses: docker/setup-buildx-action@v3
- name: 构建后端镜像
uses: docker/build-push-action@v5
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: ./backend
push: "false"
tags: juhi-api:${{ github.sha }}
- name: 构建前端镜像
uses: docker/build-push-action@v5
with:
cache-from: type=gha
cache-to: type=gha,mode=max
context: ./frontend
push: "false"
tags: juhi-frontend:${{ github.sha }}
...
|
docker-build
|
["backend-build","frontend-build"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862367
|
1771862352
|
1771862367
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
53
|
40
|
6
|
5
|
d169207d2a046f90cf861f8e805b45d3855fddc3
|
0
|
E2E 测试
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
e2e-test:
name: E2E 测试
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
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:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 初始化测试数据库
run: |
cd backend
npx prisma migrate deploy
env:
DATABASE_URL: postgresql://test:test@localhost:5432/juhi_e2e
- name: 启动后端服务
run: |
cd backend
pnpm run dev &
sleep 15
env:
DATABASE_URL: postgresql://test:test@localhost:5432/juhi_e2e
REDIS_URL: redis://localhost:6379
JWT_SECRET: e2e-test-secret-key
NODE_ENV: test
PORT: 3000
- name: 后端健康检查
run: |
curl -f http://localhost:3000/health || exit 1
- name: 安装 Playwright
run: |
cd frontend
npx playwright install --with-deps chromium
- name: 运行 E2E 测试
run: |
cd frontend
pnpm run test:e2e || true
env:
VITE_API_BASE_URL: http://localhost:3000/v1
- if: always()
name: 上传测试报告
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: frontend/playwright-report
retention-days: "7"
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: juhi_e2e
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-alpine
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
...
|
e2e-test
|
["backend-build","frontend-build"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862367
|
1771862352
|
1771862367
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
54
|
40
|
6
|
5
|
d169207d2a046f90cf861f8e805b45d3855fddc3
|
0
|
代码质量门控
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
quality-gate:
name: 代码质量门控
runs-on: ubuntu-latest
if: always()
steps:
- name: 检查所有任务状态
run: |
echo "## CI 验证结果"
echo ""
echo "| 检查项 | 状态 |"
echo "|--------|------|"
echo "| 后端测试 | ${{ needs.backend-test.result }} |"
echo "| 后端构建 | ${{ needs.backend-build.result }} |"
echo "| 前端构建 | ${{ needs.frontend-build.result }} |"
echo "| 安全审计 | ${{ needs.security-audit.result }} |"
- name: 验证门控
run: |
BACKEND_TEST="${{ needs.backend-test.result }}"
BACKEND_BUILD="${{ needs.backend-build.result }}"
FRONTEND_BUILD="${{ needs.frontend-build.result }}"
# 跳过的任务视为通过
if [ "$BACKEND_BUILD" == "failure" ] || [ "$FRONTEND_BUILD" == "failure" ]; then
echo "❌ 构建失败,代码质量门控未通过"
exit 1
fi
if [ "$BACKEND_TEST" == "failure" ]; then
echo "❌ 测试失败,代码质量门控未通过"
exit 1
fi
echo "✅ 代码质量门控通过"
...
|
quality-gate
|
["backend-test","backend-build", ["backend-test","backend-build","frontend-build","security-audit"]...
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862367
|
1771862352
|
1771862367
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
55
|
41
|
6
|
5
|
abd8cdd0283c96dc4a62fbf753d2aca2e68aa379
|
0
|
检测代码变更
|
1
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
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/**'
mobile:
- 'mobile/**'
- 'shared/**'
shared:
- 'shared/**'
workflows:
- '.github/workflows/**'
outputs:
backend: ${{ steps.filter.outputs.backend }}
frontend: ${{ steps.filter.outputs.frontend }}
mobile: ${{ steps.filter.outputs.mobile }}
shared: ${{ steps.filter.outputs.shared }}
workflows: ${{ steps.filter.outputs.workflows }}
...
|
detect-changes
|
null
|
["ubuntu-latest"]
|
35
|
3
|
1771862368
|
1771862388
|
1771862367
|
1771862388
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
56
|
41
|
6
|
5
|
abd8cdd0283c96dc4a62fbf753d2aca2e68aa379
|
0
|
安装依赖
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
setup:
name: 安装依赖
runs-on: ubuntu-latest
steps:
- name: 检出代码
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: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
e2e/node_modules
...
|
setup
|
null
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862388
|
1771862367
|
1771862388
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
57
|
41
|
6
|
5
|
abd8cdd0283c96dc4a62fbf753d2aca2e68aa379
|
0
|
共享包检查
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
shared-check:
name: 共享包检查
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.shared == 'true'
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:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: TypeScript 类型检查
run: pnpm --filter @juhi/shared run build
- name: 运行共享层单元测试
run: pnpm --filter @juhi/shared run test:coverage
- name: 上传共享层覆盖率报告
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: "false"
files: shared/coverage/lcov.info
flags: shared
- name: 验证导出
run: |
cd shared
node -e "import('./dist/index.js').then(m => console.log('✅ 共享包导出验证通过'))"
...
|
shared-check
|
["setup","detect-changes"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862388
|
1771862367
|
1771862388
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
58
|
41
|
6
|
5
|
abd8cdd0283c96dc4a62fbf753d2aca2e68aa379
|
0
|
后端代码检查
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
backend-lint:
name: 后端代码检查
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.backend == 'true'
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:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: ESLint 检查
run: pnpm --filter juhi-api run lint
- name: TypeScript 类型检查
run: pnpm --filter juhi-api run type-check
...
|
backend-lint
|
["setup","detect-changes"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862388
|
1771862367
|
1771862388
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
59
|
41
|
6
|
5
|
abd8cdd0283c96dc4a62fbf753d2aca2e68aa379
|
0
|
后端单元测试
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
backend-test:
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:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 运行单元测试
run: pnpm --filter juhi-api run test:ci
env:
DATABASE_URL: postgresql://test:test@localhost:5432/juhi_test
REDIS_URL: redis://localhost:6379
JWT_SECRET: test-secret-key
NODE_ENV: test
- name: 上传覆盖率报告
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: "false"
files: backend/coverage/lcov.info
flags: backend
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: juhi_test
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-alpine
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
...
|
backend-test
|
["backend-lint"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862388
|
1771862367
|
1771862388
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
60
|
41
|
6
|
5
|
abd8cdd0283c96dc4a62fbf753d2aca2e68aa379
|
0
|
后端构建检查
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
backend-build:
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:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 构建
run: pnpm --filter juhi-api run build
- name: 验证构建产物
run: |
if [ ! -d "backend/dist" ]; then
echo "❌ 构建产物不存在"
exit 1
fi
echo "✅ 后端构建验证通过"
...
|
backend-build
|
["backend-lint"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862388
|
1771862367
|
1771862388
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
61
|
41
|
6
|
5
|
abd8cdd0283c96dc4a62fbf753d2aca2e68aa379
|
0
|
前端代码检查
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
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
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: ESLint 检查
run: pnpm --filter juhi-frontend run lint
- name: TypeScript 类型检查
run: pnpm --filter juhi-frontend run type-check
...
|
frontend-lint
|
["setup","detect-changes"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862388
|
1771862367
|
1771862388
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
62
|
41
|
6
|
5
|
abd8cdd0283c96dc4a62fbf753d2aca2e68aa379
|
0
|
前端构建检查
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
frontend-build:
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:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: 构建
run: pnpm --filter juhi-frontend run build
- name: 验证构建产物
run: |
if [ ! -d "frontend/dist" ]; then
echo "❌ 构建产物不存在"
exit 1
fi
echo "✅ 前端构建验证通过"
- name: 上传构建产物
uses: actions/upload-artifact@v4
with:
name: frontend-dist
path: frontend/dist
retention-days: "7"
...
|
frontend-build
|
["frontend-lint"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862388
|
1771862367
|
1771862388
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
63
|
41
|
6
|
5
|
abd8cdd0283c96dc4a62fbf753d2aca2e68aa379
|
0
|
移动端检查
|
0
|
name: CI
"on":
push:
branches: name: CI
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
mobile-check:
name: 移动端检查
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.mobile == 'true'
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:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
mobile/node_modules
shared/node_modules
shared/dist
- name: ESLint 检查
run: pnpm --filter juhi-mobile run lint || true
- name: TypeScript 类型检查
run: pnpm --filter juhi-mobile run type-check || true
...
|
mobile-check
|
["setup","detect-changes"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1771862388
|
1771862367
|
1771862388
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|