refactor(api)!: 下架 v0 裸 /api/* 业务路由,统一收口到 /api/v1/* #23
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Backend CI | ||
| # A2(商业化就绪):CI 从门面变真门禁。 | ||
| # 策略:阻塞门禁保持稳定(compile + 快速 eunit + dco); | ||
| # 全量 eunit 与 dialyze 先以 continue-on-error 建立"失败基线", | ||
| # CI 干净环境实跑一次得到可信基线后,下一轮再按项目 ratchet 范式 | ||
| # (见 quality.yml)收紧为硬门禁。OTP 与 README 宣称的 28 对齐。 | ||
| on: | ||
| push: | ||
| branches: [main, dev] | ||
| pull_request: | ||
| branches: [main, dev] | ||
| workflow_dispatch: | ||
| jobs: | ||
| compile: | ||
| name: Compile Gate (OTP ${{ matrix.otp }}) | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 20 | ||
| # OTP 28 为权威版本(与 README 一致、本地开发环境一致); | ||
| # 27.3 作为向后兼容观察项,不阻塞(experimental)。 | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| otp: ["28"] | ||
| include: | ||
| - otp: "27.3" | ||
| experimental: true | ||
| continue-on-error: ${{ matrix.experimental || false }} | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| - name: Setup Erlang/OTP toolchain | ||
| uses: erlef/setup-beam@v1 | ||
| with: | ||
| otp-version: ${{ matrix.otp }} | ||
| rebar3-version: "3.24.0" | ||
| - name: Cache dependencies and build artifacts | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: | | ||
| deps | ||
| _build | ||
| .erlang.mk | ||
| .dialyzer_plt | ||
| ~/.cache/rebar3 | ||
| key: ${{ runner.os }}-otp${{ matrix.otp }}-beam-${{ hashFiles('Makefile', 'include/deps.mk') }} | ||
| - name: Check duplicate module names | ||
| run: bash scripts/check_duplicate_modules.sh | ||
| - name: Compile | ||
| run: IMBOYENV=local make test-build | ||
| moment-eunit: | ||
| name: Moment EUnit Gate | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 20 | ||
| needs: [compile] | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| - name: Setup Erlang/OTP toolchain | ||
| uses: erlef/setup-beam@v1 | ||
| with: | ||
| otp-version: "28" | ||
| rebar3-version: "3.24.0" | ||
| - name: Cache dependencies and build artifacts | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: | | ||
| deps | ||
| _build | ||
| .erlang.mk | ||
| .dialyzer_plt | ||
| ~/.cache/rebar3 | ||
| key: ${{ runner.os }}-otp28-beam-${{ hashFiles('Makefile', 'include/deps.mk') }} | ||
| - name: Run Moment Targeted EUnit | ||
| run: | | ||
| IMBOYENV=local make eunit EUNIT_MODS='moment_repo_tests moment_logic_tests moment_handler_tests adm_moment_handler_tests' | ||
| # ---------------------------------------------------------------- | ||
| # 全量 EUnit — 基线收集(continue-on-error,暂不阻塞) | ||
| # 目的:在 CI 干净环境实跑全部 test/*_tests,产出真实通过/失败基线。 | ||
| # 收紧计划:基线明确后改为 ratchet(失败数只准减不准增),移除 continue-on-error。 | ||
| # ---------------------------------------------------------------- | ||
| full-eunit: | ||
| name: Full EUnit (baseline, non-blocking) | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 40 | ||
| needs: [compile] | ||
| continue-on-error: true | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| - name: Setup Erlang/OTP toolchain | ||
| uses: erlef/setup-beam@v1 | ||
| with: | ||
| otp-version: "28" | ||
| rebar3-version: "3.24.0" | ||
| - name: Cache dependencies and build artifacts | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: | | ||
| deps | ||
| _build | ||
| .erlang.mk | ||
| .dialyzer_plt | ||
| ~/.cache/rebar3 | ||
| key: ${{ runner.os }}-otp28-beam-${{ hashFiles('Makefile', 'include/deps.mk') }} | ||
| - name: Run full EUnit suite | ||
| run: | | ||
| set -o pipefail | ||
| IMBOYENV=local make eunit 2>&1 | tee eunit-full.log | ||
| - name: Summarize EUnit result | ||
| if: always() | ||
| run: | | ||
| echo "## Full EUnit baseline" >> "$GITHUB_STEP_SUMMARY" | ||
| # erlang.mk/eunit 汇总行形如 "Failed: N. ... Passed: M." | ||
| grep -iE 'failed|passed|aborted|cancelled' eunit-full.log | tail -20 >> "$GITHUB_STEP_SUMMARY" || true | ||
| - name: Upload EUnit log | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: eunit-full-log | ||
| path: eunit-full.log | ||
| retention-days: 14 | ||
| # ---------------------------------------------------------------- | ||
| # Dialyzer — 基线收集(continue-on-error,暂不阻塞) | ||
| # Makefile 已设 DIALYZER_WARNINGS ?= 50 阈值;先观察 CI 实际告警数, | ||
| # 再据此把阈值收敛为 ratchet。 | ||
| # ---------------------------------------------------------------- | ||
| dialyze: | ||
| name: Dialyzer (baseline, non-blocking) | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 40 | ||
| needs: [compile] | ||
| continue-on-error: true | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| - name: Setup Erlang/OTP toolchain | ||
| uses: erlef/setup-beam@v1 | ||
| with: | ||
| otp-version: "28" | ||
| rebar3-version: "3.24.0" | ||
| - name: Cache dependencies, build artifacts and PLT | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: | | ||
| deps | ||
| _build | ||
| .erlang.mk | ||
| .dialyzer_plt | ||
| ~/.cache/rebar3 | ||
| key: ${{ runner.os }}-otp28-dialyzer-${{ hashFiles('Makefile', 'include/deps.mk') }} | ||
| - name: Run Dialyzer | ||
| run: | | ||
| set -o pipefail | ||
| IMBOYENV=local make dialyze 2>&1 | tee dialyze.log | ||
| - name: Summarize Dialyzer result | ||
| if: always() | ||
| run: | | ||
| echo "## Dialyzer baseline" >> "$GITHUB_STEP_SUMMARY" | ||
| warn_count="$(grep -ciE 'warning|Warning' dialyze.log || true)" | ||
| echo "Dialyzer warning lines: ${warn_count} (Makefile threshold DIALYZER_WARNINGS=50)" >> "$GITHUB_STEP_SUMMARY" | ||
| - name: Upload Dialyzer log | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: dialyze-log | ||
| path: dialyze.log | ||
| retention-days: 14 | ||
| # ---------------------------------------------------------------- | ||
| # Xref — 零容忍 ratchet(阻塞,undefined 数必须为 0) | ||
| # 完整编译后实跑 make xref,任何"调用了不存在函数"均视为 CI 失败。 | ||
| # 必须在完整 build 之后运行:beam 不全会产生假阳性(mutual undefined)。 | ||
| # 基线历史:2026-06-13 初始=42,同日全部修复,ratchet 目标 = 0。 | ||
| # ---------------------------------------------------------------- | ||
| xref: | ||
| name: Xref undefined-calls (ratchet: 0 allowed) | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 30 | ||
| needs: [compile] | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| - name: Setup Erlang/OTP toolchain | ||
| uses: erlef/setup-beam@v1 | ||
| with: | ||
| otp-version: "28" | ||
| rebar3-version: "3.24.0" | ||
| - name: Cache dependencies and build artifacts | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: | | ||
| deps | ||
| _build | ||
| .erlang.mk | ||
| .dialyzer_plt | ||
| ~/.cache/rebar3 | ||
| key: ${{ runner.os }}-otp28-beam-${{ hashFiles('Makefile', 'include/deps.mk') }} | ||
| - name: Run Xref (erlang.mk 会先完整编译再 xref) | ||
| run: | | ||
| set -o pipefail | ||
| IMBOYENV=local make xref 2>&1 | tee xref.log || true | ||
| - name: Enforce zero undefined calls | ||
| run: | | ||
| undef_count="$(grep -c 'Undefined function' xref.log || true)" | ||
| echo "Undefined function calls: ${undef_count}" | ||
| if [ "${undef_count}" -gt 0 ]; then | ||
| echo "ERROR: xref ratchet failed — ${undef_count} undefined call(s) detected:" >&2 | ||
| grep 'Undefined function' xref.log | sort -u >&2 | ||
| exit 1 | ||
| fi | ||
| - name: Summarize Xref result | ||
| if: always() | ||
| run: | | ||
| echo "## Xref undefined-calls (ratchet: 0 allowed)" >> "$GITHUB_STEP_SUMMARY" | ||
| undef_count="$(grep -c 'Undefined function' xref.log || true)" | ||
| echo "Undefined function calls: ${undef_count} (ratchet 目标 = 0;2026-06-13 从 42 全修)" >> "$GITHUB_STEP_SUMMARY" | ||
| grep 'Undefined function' xref.log | sort -u >> "$GITHUB_STEP_SUMMARY" || true | ||
| - name: Upload Xref log | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: xref-log | ||
| path: xref.log | ||
| retention-days: 14 | ||
| # ---------------------------------------------------------------- | ||
| # DCO — 仅 PR 检查,验证所有 commits 带有 Signed-off-by | ||
| # ---------------------------------------------------------------- | ||
| dco-check: | ||
| name: DCO check | ||
| runs-on: ubuntu-latest | ||
| if: github.event_name == 'pull_request' | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| - name: DCO check | ||
| uses: dco-org/dco-action@v1 | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||