Some checks failed
- W22.1: gcovr 覆盖率度量 + CI coverage job(40% 阈值 warning) - W22.2: network_plugin 单元测试(parse_headers_json/extract_host_port/SSE/异常保护) - W22.3: Tool Calling 流式反馈(chat_stream + "[工具调用]/[工具结果]" 状态行) - W22.4: --prompt stdin pipe(--prompt - 从 stdin 读取) - W22.5: session 路径健壮化(static 缓存 + mkdir + fallback) - W22.6: 插件依赖拓扑静态校验(validate_dependencies 循环/缺失检测) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
331 lines
14 KiB
YAML
331 lines
14 KiB
YAML
name: CI
|
||
|
||
on:
|
||
push:
|
||
branches: [master]
|
||
pull_request:
|
||
branches: [master]
|
||
|
||
env:
|
||
CMAKE_BUILD_PARALLEL_LEVEL: 0
|
||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||
CCACHE_MAXSIZE: 256M
|
||
|
||
jobs:
|
||
# ── 动态矩阵 ──────────────────────────────────────────────
|
||
# PR 仅跑 Ubuntu 节省 minutes;push master 跑全矩阵 Ubuntu + Windows
|
||
matrix:
|
||
name: Determine matrix
|
||
runs-on: ubuntu-24.04
|
||
outputs:
|
||
os: ${{ steps.set-matrix.outputs.os }}
|
||
steps:
|
||
- id: set-matrix
|
||
shell: bash
|
||
run: |
|
||
if [ "${{ github.event_name }}" = "push" ] && [ "${{ github.ref }}" = "refs/heads/master" ]; then
|
||
echo "os=[\"ubuntu-24.04\",\"windows-2025\"]" >> "$GITHUB_OUTPUT"
|
||
else
|
||
echo "os=[\"ubuntu-24.04\"]" >> "$GITHUB_OUTPUT"
|
||
fi
|
||
|
||
# ── 构建 & 测试 ───────────────────────────────────────────
|
||
build:
|
||
name: ${{ matrix.os }} / ${{ matrix.build_type }}
|
||
needs: matrix
|
||
strategy:
|
||
fail-fast: false
|
||
matrix:
|
||
os: ${{ fromJSON(needs.matrix.outputs.os) }}
|
||
build_type: [Release]
|
||
runs-on: ${{ matrix.os }}
|
||
|
||
steps:
|
||
# ── 1. 源码检出 ──────────────────────────────────────
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 1
|
||
|
||
# ── 2. 平台编译工具链 ─────────────────────────────────
|
||
# Ubuntu: clang-18 + Ninja + ccache
|
||
- name: Install toolchain (Ubuntu)
|
||
if: runner.os == 'Linux'
|
||
run: |
|
||
sudo apt-get update -qq
|
||
sudo apt-get install -y -qq clang-18 ninja-build ccache
|
||
echo "CC=clang-18" >> $GITHUB_ENV
|
||
echo "CXX=clang++-18" >> $GITHUB_ENV
|
||
|
||
# Windows: LLVM (clang-cl) + Ninja + ccache
|
||
- name: Install toolchain (Windows)
|
||
if: runner.os == 'Windows'
|
||
shell: bash
|
||
run: |
|
||
choco install -y llvm ninja ccache --no-progress 2>/dev/null || true
|
||
# Add clang-cl to PATH (both possible locations)
|
||
# Prefer choco-installed LLVM; fall back to VS-bundled clang-cl
|
||
if [ -d "/c/Program Files/LLVM/bin" ]; then
|
||
echo "/c/Program Files/LLVM/bin" >> $GITHUB_PATH
|
||
elif [ -d "/c/Program Files/Microsoft Visual Studio/2026/Enterprise/VC/Tools/Llvm/x64/bin" ]; then
|
||
echo "/c/Program Files/Microsoft Visual Studio/2026/Enterprise/VC/Tools/Llvm/x64/bin" >> $GITHUB_PATH
|
||
elif [ -d "/c/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Tools/Llvm/x64/bin" ]; then
|
||
echo "/c/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Tools/Llvm/x64/bin" >> $GITHUB_PATH
|
||
fi
|
||
echo "CC=clang-cl" >> $GITHUB_ENV
|
||
echo "CXX=clang-cl" >> $GITHUB_ENV
|
||
|
||
# ── 3. ccache 缓存恢复 ────────────────────────────────
|
||
- name: Cache ccache
|
||
uses: actions/cache@v4
|
||
with:
|
||
path: ${{ env.CCACHE_DIR }}
|
||
key: ${{ runner.os }}-ccache-${{ matrix.build_type }}-${{ github.run_id }}
|
||
restore-keys: |
|
||
${{ runner.os }}-ccache-${{ matrix.build_type }}-
|
||
${{ runner.os }}-ccache-
|
||
|
||
# ── 4. Python + Conan ─────────────────────────────────
|
||
- name: Setup Python
|
||
uses: actions/setup-python@v5
|
||
with:
|
||
python-version: '3.12'
|
||
|
||
- name: Install Conan
|
||
run: pip install conan
|
||
|
||
# ── 5. Conan 依赖缓存 ─────────────────────────────────
|
||
- name: Cache Conan
|
||
uses: actions/cache@v4
|
||
with:
|
||
path: |
|
||
~/.conan2
|
||
~/.conan2/p
|
||
key: ${{ runner.os }}-conan-${{ matrix.build_type }}-${{ hashFiles('deps/conanfile.txt') }}
|
||
restore-keys: |
|
||
${{ runner.os }}-conan-${{ matrix.build_type }}-
|
||
${{ runner.os }}-conan-
|
||
|
||
# ── 6. Conan 依赖安装 ─────────────────────────────────
|
||
- name: Install Conan dependencies
|
||
shell: bash
|
||
run: |
|
||
conan profile detect --force
|
||
conan install deps --build=missing -s build_type=${{ matrix.build_type }}
|
||
|
||
# ── 7. CMake 配置 ─────────────────────────────────────
|
||
- name: Configure CMake
|
||
shell: bash
|
||
run: |
|
||
cmake --preset ci-release \
|
||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||
|
||
# ── 8. 构建(含计时) ─────────────────────────────────
|
||
- name: Build
|
||
id: build
|
||
shell: bash
|
||
run: |
|
||
echo "::group::Build (${{ matrix.os }})"
|
||
START_NS=$(date +%s%N 2>/dev/null || echo 0)
|
||
START_S=$(date +%s)
|
||
cmake --build --preset ci-release --config ${{ matrix.build_type }}
|
||
END_S=$(date +%s)
|
||
END_NS=$(date +%s%N 2>/dev/null || echo 0)
|
||
DURATION=$((END_S - START_S))
|
||
echo "::endgroup::"
|
||
echo "duration=${DURATION}" >> $GITHUB_OUTPUT
|
||
echo "Build wall time: ${DURATION}s"
|
||
|
||
# ── 9. ccache 统计 ────────────────────────────────────
|
||
- name: ccache stats
|
||
if: always()
|
||
shell: bash
|
||
run: |
|
||
ccache -s || echo "ccache stats unavailable"
|
||
ccache -z || true
|
||
|
||
# ── 10. 测试 ──────────────────────────────────────────
|
||
- name: Test
|
||
shell: bash
|
||
run: ctest --preset ci-release -C ${{ matrix.build_type }} --output-on-failure
|
||
|
||
# ── 11. 构建时间摘要 ──────────────────────────────────
|
||
- name: Build time summary
|
||
if: always()
|
||
shell: bash
|
||
run: |
|
||
DURATION="${{ steps.build.outputs.duration }}"
|
||
echo "| Platform | Compiler | Build Time |" >> $GITHUB_STEP_SUMMARY
|
||
echo "|----------|----------|-----------|" >> $GITHUB_STEP_SUMMARY
|
||
echo "| ${{ matrix.os }} | ${{ (runner.os == 'Linux' && 'clang-18') || 'clang-cl' }} | ${DURATION}s |" >> $GITHUB_STEP_SUMMARY
|
||
echo "CI build: ${{ matrix.os }} / ${{ (runner.os == 'Linux' && 'clang-18') || 'clang-cl' }} wall time ${DURATION}s"
|
||
|
||
# ── Sanitizer (PR-only, Linux clang-18, no ccache) ───────
|
||
sanitize:
|
||
name: Sanitizer (ASan+UBSan) / ubuntu-24.04
|
||
if: github.event_name == 'pull_request'
|
||
runs-on: ubuntu-24.04
|
||
|
||
steps:
|
||
# ── 1. 源码检出 ──────────────────────────────────────
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 1
|
||
|
||
# ── 2. 工具链 (clang-18) ─────────────────────────────
|
||
- name: Install toolchain (Ubuntu)
|
||
run: |
|
||
sudo apt-get update -qq
|
||
sudo apt-get install -y -qq clang-18 ninja-build
|
||
echo "CC=clang-18" >> $GITHUB_ENV
|
||
echo "CXX=clang++-18" >> $GITHUB_ENV
|
||
|
||
# ── 3. Python + Conan ─────────────────────────────────
|
||
- name: Setup Python
|
||
uses: actions/setup-python@v5
|
||
with:
|
||
python-version: '3.12'
|
||
|
||
- name: Install Conan
|
||
run: pip install conan
|
||
|
||
# ── 4. Conan 依赖缓存 ─────────────────────────────────
|
||
- name: Cache Conan
|
||
uses: actions/cache@v4
|
||
with:
|
||
path: |
|
||
~/.conan2
|
||
~/.conan2/p
|
||
key: ${{ runner.os }}-conan-Release-${{ hashFiles('deps/conanfile.txt') }}
|
||
restore-keys: |
|
||
${{ runner.os }}-conan-Release-
|
||
${{ runner.os }}-conan-
|
||
|
||
# ── 5. Conan 依赖安装 ─────────────────────────────────
|
||
- name: Install Conan dependencies
|
||
shell: bash
|
||
run: |
|
||
conan profile detect --force
|
||
conan install deps --build=missing -s build_type=Release
|
||
|
||
# ── 6. CMake 配置 ─────────────────────────────────────
|
||
- name: Configure CMake (Sanitizer)
|
||
shell: bash
|
||
run: cmake --preset ci-sanitize
|
||
|
||
# ── 7. 构建 ───────────────────────────────────────────
|
||
- name: Build (Sanitizer)
|
||
shell: bash
|
||
run: cmake --build --preset ci-sanitize
|
||
|
||
# ── 8. 测试 ──────────────────────────────────────────
|
||
- name: Test (Sanitizer)
|
||
shell: bash
|
||
run: ctest --preset ci-sanitize --output-on-failure
|
||
|
||
# ── Coverage (PR + push master, Linux clang-18, gcovr) ──
|
||
coverage:
|
||
name: Coverage (gcovr) / ubuntu-24.04
|
||
runs-on: ubuntu-24.04
|
||
|
||
steps:
|
||
# ── 1. 源码检出 ──────────────────────────────────────
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 1
|
||
|
||
# ── 2. 工具链 (clang-18) ─────────────────────────────
|
||
- name: Install toolchain (Ubuntu)
|
||
run: |
|
||
sudo apt-get update -qq
|
||
sudo apt-get install -y -qq clang-18 ninja-build
|
||
echo "CC=clang-18" >> $GITHUB_ENV
|
||
echo "CXX=clang++-18" >> $GITHUB_ENV
|
||
|
||
# ── 3. Python + Conan ─────────────────────────────────
|
||
- name: Setup Python
|
||
uses: actions/setup-python@v5
|
||
with:
|
||
python-version: '3.12'
|
||
|
||
- name: Install Conan + gcovr
|
||
run: pip install conan gcovr
|
||
|
||
# ── 4. Conan 依赖缓存 ─────────────────────────────────
|
||
- name: Cache Conan
|
||
uses: actions/cache@v4
|
||
with:
|
||
path: |
|
||
~/.conan2
|
||
~/.conan2/p
|
||
key: ${{ runner.os }}-conan-Release-${{ hashFiles('deps/conanfile.txt') }}
|
||
restore-keys: |
|
||
${{ runner.os }}-conan-Release-
|
||
${{ runner.os }}-conan-
|
||
|
||
# ── 5. Conan 依赖安装 ─────────────────────────────────
|
||
- name: Install Conan dependencies
|
||
shell: bash
|
||
run: |
|
||
conan profile detect --force
|
||
conan install deps --build=missing -s build_type=Release
|
||
|
||
# ── 6. CMake 配置 ─────────────────────────────────────
|
||
- name: Configure CMake (Coverage)
|
||
shell: bash
|
||
run: cmake --preset ci-coverage
|
||
|
||
# ── 7. 构建 ───────────────────────────────────────────
|
||
- name: Build (Coverage)
|
||
shell: bash
|
||
run: cmake --build --preset ci-coverage
|
||
|
||
# ── 8. 测试 ──────────────────────────────────────────
|
||
- name: Test (Coverage)
|
||
shell: bash
|
||
run: ctest --preset ci-coverage --output-on-failure
|
||
|
||
# ── 9. 覆盖率报告 ────────────────────────────────────
|
||
- name: Coverage report
|
||
id: coverage
|
||
shell: bash
|
||
run: |
|
||
gcovr -r . --object-directory=build/ci-coverage \
|
||
--gcov-executable "llvm-cov-18 gcov" \
|
||
--print-summary > coverage_summary.txt 2>&1 || true
|
||
cat coverage_summary.txt
|
||
# Extract line coverage percentage
|
||
LINE_COV=$(grep -oP 'lines:\s*\K[\d.]+' coverage_summary.txt || echo "0")
|
||
echo "line_rate=${LINE_COV}" >> $GITHUB_OUTPUT
|
||
# Also generate HTML report
|
||
mkdir -p build/ci-coverage/coverage
|
||
gcovr -r . --object-directory=build/ci-coverage \
|
||
--gcov-executable "llvm-cov-18 gcov" \
|
||
--html --html-details \
|
||
-o build/ci-coverage/coverage/index.html || true
|
||
echo "HTML report: build/ci-coverage/coverage/index.html"
|
||
|
||
# ── 10. 覆盖率摘要 + 阈值门禁 ─────────────────────────
|
||
- name: Coverage summary
|
||
if: always()
|
||
shell: bash
|
||
run: |
|
||
LINE_COV="${{ steps.coverage.outputs.line_rate }}"
|
||
THRESHOLD=40
|
||
echo "## Coverage Report" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "| Metric | Value | Threshold | Status |" >> $GITHUB_STEP_SUMMARY
|
||
echo "|--------|-------|-----------|--------|" >> $GITHUB_STEP_SUMMARY
|
||
if [ -z "$LINE_COV" ] || [ "$LINE_COV" = "0" ]; then
|
||
echo "| Line Coverage | N/A | ${THRESHOLD}% | :grey_question: (no data) |" >> $GITHUB_STEP_SUMMARY
|
||
elif awk "BEGIN {exit !($LINE_COV < $THRESHOLD)}"; then
|
||
echo "| Line Coverage | ${LINE_COV}% | ${THRESHOLD}% | :warning: BELOW THRESHOLD |" >> $GITHUB_STEP_SUMMARY
|
||
echo "::warning title=Coverage below threshold::Line coverage ${LINE_COV}% is below ${THRESHOLD}% threshold"
|
||
else
|
||
echo "| Line Coverage | ${LINE_COV}% | ${THRESHOLD}% | :white_check_mark: OK |" >> $GITHUB_STEP_SUMMARY
|
||
echo "Line coverage ${LINE_COV}% >= ${THRESHOLD}% threshold - OK"
|
||
fi
|