| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- # =============================================================================
- # 浠艾福 (XAF) — 最小 CI 管线(GitLab CI,仓库根,自动加载)
- # -----------------------------------------------------------------------------
- # 落地:2026-11-06(最小 CI 管线搭建)
- # 追加:2026-11-07(EVD-6 持续回归:契约 JUnit / langgraph pytest / Playwright e2e / tests jest)
- # 重设计:2026-11-07(B-40 修复——CI 软门禁升级为「两级硬门禁」)
- # 前置:remote = http://git.iwintrue.com/liaoxg/cfc(GitLab 系自托管)
- #
- # ███ B-40 两级门禁设计(2026-11-07 落地,替代原 4 个 allow_failure 软门禁)███
- # - test-blocking(全绿子集):必须过。任一 blocking job 红 → 流水线红。
- # 含 backend-g0-compile / frontend-jest / web-jest / backend-blocking-junit
- # / langgraph-blocking-pytest。
- # - test-observed(已知红 / 环境依赖):allow_failure: true,失败不拦截,
- # 但始终产出 junit 趋势(artifacts when: always),供测试侧逐轮跟踪。
- # 含 backend-observed-junit / e2e-playwright-observed / tests-jest-observed。
- # - 「integration 包按类白名单逐批转入 blocking」机制:
- # * 后端 blocking 用 `-Dtest='!${BACKEND_OBSERVED_CLASSES}'` 排除「已知红类」,
- # 其余全跑——即所有**当前全绿**的 integration 类已自动进入 blocking(首批);
- # * 每修好一个红类,就从 BACKEND_OBSERVED_CLASSES 移除该类 → 下轮自动转入
- # blocking(逐批增量);blocking 覆盖例数随之上升,直至 observed 清空。
- # - 覆盖口径:blocking 覆盖 = 全量 − observed(已知红)≥ 当前全量 80%
- # (当前红类 33 类 / 红例 115 例 [failures+errors,第 69 轮干净 HEAD 实测],
- # blocking 覆盖例数 ≥92%,满足 B-40 闭环条件)。
- #
- # 🔴 关键坑(必须保留):cfc-backend/pom.xml 第 28 行 <skipTests>true</skipTests>,
- # 直接 `mvn test` 会**静默跳过全部测试(假绿)**。因此后端 job 必须显式
- # `-DskipTests=false`,并加「0 XML 即失败」守卫(B-39)。
- #
- # 🔴 启用前置(本机实测,runner 侧待平台核实):
- # 1) runner 需 JDK8 + Maven + node18/20/22 + npm + Python3.11+ + 可拉依赖网络
- # 2) blocking job 已改 `when: on_success`(自动触发,硬门禁);首次跑通前若
- # runner 能力未备,可临时将 blocking job 改回 `when: manual` 人工验证一次,
- # 但「红即拦」语义不变(blocking 均未设 allow_failure)。
- # 3) 若 runner .m2 已预热且无外网,可在 mvn 命令加 `-o`(离线)
- # 4) e2e-playwright-observed 需 runner 具备 chromium 系统依赖(或 root 跑
- # `npx playwright install --with-deps chromium`)
- # 5) tests-jest-observed 依赖 npm>=10 解析 "npm:@vue/babel-plugin-jsx@^1.1.1"(node22 自带 npm10)
- # -----------------------------------------------------------------------------
- # 设计说明(G0/G1 分层基线):
- # - G0 编译门禁(backend-g0-compile,必绿,最快信号)
- # - G1 两级回归(B-40):
- # * test-blocking:全绿子集(前端 jest / 管理端 jest / 后端非红类 / langgraph pytest)
- # * test-observed:已知红或环境依赖(后端红类 / e2e CI 安全模式 / tests jest)
- # - e2e-playwright-observed:**CI 安全模式**——只做 `--list` 收集校验 + headless 冒烟;
- # 真实 UI e2e 依赖部署环境 + DB(globalSetup 会重置 192.168.16.251 测试库,
- # **严禁**在 CI 开启 playwright.config.js 默认 globalSetup)
- # =============================================================================
- stages:
- - build
- - test
- variables:
- MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
- # ---------------------------------------------------------------------------
- # 后端「已知红类」(test-observed 白名单,逗号分隔的简单类名)。
- # 依据:第 69 轮全量实跑(干净 HEAD)红类快照(33 类,surefire-reports 提取)+ B-38 归因;
- # 修好一个类就从下方列表移除一个 → 该类下轮自动转入 test-blocking(逐批增量)。
- # 说明:`-Dtest='!${BACKEND_OBSERVED_CLASSES}'` 只排除这些类,其余全跑(含全绿 integration 类)。
- # ---------------------------------------------------------------------------
- BACKEND_OBSERVED_CLASSES: "AdminFamilyOverviewControllerTest,ArticleControllerTest,ArticleWorkflowTest,AuthControllerTest,CfCommissionServiceSettleTest,DailyCheckinStreakFlowTest,DimensionRegistryMapContractTest,DimensionScoreServiceImplTest,EnergySystemFlowTest,FamilyAdminOverviewServiceTest,FamilyControllerTest,FamilyJoinRequestServiceReferrerBindTest,FortuneServiceTest,GrowthRecordSyncFlowTest,GuideFamilyTaskControllerTest,GuideModuleIntegrationTest,GuideOrderControllerTest,GuideRolePermissionTest,GuideTeamControllerTest,MembershipPaySwitchTest,MindFortuneControllerTest,OrchestrationEngineTest,OrchestrationIntegrationTest,PaymentControllerTest,PaymentServiceORDRoutingTest,PlannerBindInviteFlowTest,ProductControllerTest,ProductOrderControllerTest,ProductOrderServiceFulfillmentMultiModeTest,ProductOrderServiceUpdateExpressFieldTest,StatsControllerTest,UserServiceFamilyNameLinkTest,WishControllerTest"
- cache:
- key: "$CI_COMMIT_REF_SLUG"
- paths:
- - .m2/repository
- - cfc-frontend/node_modules/
- - cfc-web/node_modules/
- - tests/node_modules/
- # ---------------------------------------------------------------------------
- # Job 1 — 后端 G0 编译门禁(test-blocking)
- # ---------------------------------------------------------------------------
- backend-g0-compile:
- stage: build
- when: on_success # B-40:硬门禁自动触发(红即拦)
- cache:
- key: "$CI_COMMIT_REF_SLUG"
- paths:
- - .m2/repository
- script:
- - cd cfc-backend
- # 必须 -DskipTests=false 覆盖 pom 默认假绿(pom.xml:28)
- - mvn test-compile -DskipTests=false
- artifacts:
- when: always
- expire_in: 7 days
- paths:
- - cfc-backend/target/classes/
- # ---------------------------------------------------------------------------
- # Job 2 — 小程序前端(cfc-frontend)jest 单测(test-blocking)
- # ---------------------------------------------------------------------------
- frontend-jest:
- stage: test
- when: on_success # B-40:硬门禁自动触发(红即拦)
- cache:
- key: "$CI_COMMIT_REF_SLUG"
- paths:
- - cfc-frontend/node_modules/
- script:
- - cd cfc-frontend
- - npm ci || npm install
- - npx jest --ci
- artifacts:
- when: always
- expire_in: 7 days
- reports:
- junit:
- - cfc-frontend/junit.xml
- paths:
- - cfc-frontend/coverage/
- # ---------------------------------------------------------------------------
- # Job 3 — 管理端(cfc-web)jest 单测(test-blocking)
- # ---------------------------------------------------------------------------
- web-jest:
- stage: test
- when: on_success # B-40:硬门禁自动触发(红即拦)
- cache:
- key: "$CI_COMMIT_REF_SLUG"
- paths:
- - cfc-web/node_modules/
- script:
- - cd cfc-web
- - npm ci || npm install
- - npx jest --ci
- artifacts:
- when: always
- expire_in: 7 days
- reports:
- junit:
- - cfc-web/junit.xml
- paths:
- - cfc-web/coverage/
- # ---------------------------------------------------------------------------
- # Job 4 — 后端契约/单测 JUnit · test-blocking(全绿子集,必须过)
- # ---------------------------------------------------------------------------
- # - 必须 -DskipTests=false 覆盖 pom:28 假绿(否则 mvn test 静默跳测 = 假绿)
- # - 仅排除 BACKEND_OBSERVED_CLASSES(已知红类);其余全跑,**含全绿 integration 类**,
- # 即「integration 按类白名单逐批转入 blocking」的首批。
- # - B-39 守卫:surefire 0 个 XML 视为假绿,直接失败(红即拦)。
- # ---------------------------------------------------------------------------
- backend-blocking-junit:
- stage: test
- when: on_success # B-40:硬门禁自动触发(红即拦)
- cache:
- key: "$CI_COMMIT_REF_SLUG"
- paths:
- - .m2/repository
- script:
- - cd cfc-backend
- # 必须 -DskipTests=false(pom.xml:28 默认 true = 假绿);只排除已知红类,其余全跑
- - mvn -B test -DskipTests=false "-Dtest=!${BACKEND_OBSERVED_CLASSES}"
- # B-39 守卫:0 个 surefire XML = 零执行假绿 → 失败
- - test "$(find target/surefire-reports -name 'TEST-*.xml' | wc -l)" -gt 0 || (echo "B-39 假绿守卫:surefire 未产出任何 TEST-*.xml" && exit 1)
- artifacts:
- when: always
- expire_in: 7 days
- reports:
- junit:
- - cfc-backend/target/surefire-reports/TEST-*.xml
- paths:
- - cfc-backend/target/surefire-reports/
- # ---------------------------------------------------------------------------
- # Job 4b — 后端「已知红类」JUnit · test-observed(allow_failure,产出趋势)
- # ---------------------------------------------------------------------------
- # - 只跑 BACKEND_OBSERVED_CLASSES(红类),allow_failure 不拦截;
- # 每轮产生 junit 供测试侧看红例数是否下降(趋势)。
- # - 修好一个类 → 从 BACKEND_OBSERVED_CLASSES 移除 → 下轮自动转入 blocking。
- # ---------------------------------------------------------------------------
- backend-observed-junit:
- stage: test
- when: on_success
- allow_failure: true # 已知红,失败不拦截,仅产出趋势
- cache:
- key: "$CI_COMMIT_REF_SLUG"
- paths:
- - .m2/repository
- script:
- - cd cfc-backend
- - mvn -B test -DskipTests=false "-Dtest=${BACKEND_OBSERVED_CLASSES}"
- after_script:
- - echo "observed 红类趋势见 surefire-reports(红例数应逐轮下降)" || true
- artifacts:
- when: always
- expire_in: 7 days
- reports:
- junit:
- - cfc-backend/target/surefire-reports/TEST-*.xml
- paths:
- - cfc-backend/target/surefire-reports/
- # ---------------------------------------------------------------------------
- # Job 5 — cfc-langgraph pytest · test-blocking(B-34 闭环后全绿,硬门禁)
- # ---------------------------------------------------------------------------
- # - conftest 自动 import app.main(需全量依赖,requirements_frozen.txt 锁版本)
- # - --ignore=tests/qna(test_graph.py 引用不存在的 src.qna → collection error)
- # - B-34/B-35/B-37 修复后 67 轮起实测 51 passed / 12 skipped / 0 failed → 转硬门禁。
- # - 注意:tests_contract/ 下的 B-41 flaky(TestGrowthReportInterpretB04)不在本 job
- # 的 `tests/` 范围内,不影响门禁;该 flaky 由测试侧单独跟踪(B-41)。
- # ---------------------------------------------------------------------------
- langgraph-blocking-pytest:
- stage: test
- when: on_success # B-40:硬门禁自动触发(红即拦)
- cache:
- key: "$CI_COMMIT_REF_SLUG"
- paths:
- - cfc-langgraph/.venv/
- script:
- - cd cfc-langgraph
- - python3 -m venv .venv || true
- - . .venv/bin/activate
- - pip install -q -r requirements_frozen.txt
- - python -m pytest tests/ -v --ignore=tests/qna --junitxml=junit.xml -p no:cacheprovider
- artifacts:
- when: always
- expire_in: 7 days
- reports:
- junit:
- - cfc-langgraph/junit.xml
- paths:
- - cfc-langgraph/junit.xml
- # ---------------------------------------------------------------------------
- # Job 6 — Playwright e2e(CI 安全模式)· test-observed(allow_failure,产出趋势)
- # ---------------------------------------------------------------------------
- # ⚠️ 严禁在 CI 使用 tests/playwright.config.js(其 globalSetup 会重置远程
- # 192.168.16.251 测试库)。CI 采用安全模式:
- # 1) `npx playwright test --list` — 校验 74 spec / 2418 用例可收集
- # 2) `-c playwright.config.smoke.js ci-smoke` — headless chromium 真实拉起冒烟
- # 真实 UI e2e 依赖部署环境 + DB(cfc.iwintrue.com),由测试负责人手动跑。
- # B-40:真实 e2e 未授权/环境依赖 → 归 test-observed(allow_failure),
- # 但 test-results 每轮归档供趋势跟踪。
- # ---------------------------------------------------------------------------
- e2e-playwright-observed:
- stage: test
- when: on_success
- allow_failure: true # 环境依赖(部署环境+DB),失败不拦截,仅产出趋势
- cache:
- key: "$CI_COMMIT_REF_SLUG"
- paths:
- - tests/node_modules/
- script:
- - cd tests
- - npm ci || npm install
- - npx playwright install chromium || true
- # CI 安全模式:只做收集校验 + headless 冒烟(均不触发远程 DB 重置)
- - npx playwright test --list
- - npx playwright test e2e/ci-smoke.spec.js -c playwright.config.smoke.js
- artifacts:
- when: always
- expire_in: 7 days
- paths:
- - tests/test-results/
- # ---------------------------------------------------------------------------
- # Job 7 — tests/ 目录 jest(unit + integration)· test-observed(allow_failure)
- # ---------------------------------------------------------------------------
- # - tests/jest.config.js 依赖 cfc-frontend/__tests__/setup.js(vue),
- # 需先装 cfc-frontend 依赖;npm>=10 才能解析 "npm:@vue/babel-plugin-jsx@^1.1.1"
- # 本机 npm9.2.0 验证失败(node22 自带 npm10 可装)
- # - integration 部分需后端 API(localhost:9082)在 CI 无后端时仅跑能跑的;
- # 当前 B-36 下根级黑盒 23 例全 skip → 归 test-observed(allow_failure)。
- # ---------------------------------------------------------------------------
- tests-jest-observed:
- stage: test
- when: on_success
- allow_failure: true # 需 npm10 + cfc-frontend(vue) 依赖;integration 需后端;B-36 全 skip
- cache:
- key: "$CI_COMMIT_REF_SLUG"
- paths:
- - tests/node_modules/
- - cfc-frontend/node_modules/
- script:
- - cd cfc-frontend && npm ci || npm install # setup.js 需要 vue
- - cd ../tests && npm ci || npm install
- - npx jest --ci
|