Skip to content

refactor(api)!: 下架 v0 裸 /api/* 业务路由,统一收口到 /api/v1/* #23

refactor(api)!: 下架 v0 裸 /api/* 业务路由,统一收口到 /api/v1/*

refactor(api)!: 下架 v0 裸 /api/* 业务路由,统一收口到 /api/v1/* #23

Workflow file for this run

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)

Check failure on line 203 in .github/workflows/backend-ci.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/backend-ci.yml

Invalid workflow file

You have an error in your yaml syntax on line 203
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 }}