Skip to content

CI/CD 与 GitHub Actions

完整的 C++ CI/CD 流水线:多平台构建、静态分析、Sanitizers 测试、性能基准、Docker 发布,一次提交全自动验证。

完整 CI 配置

yaml
# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  VCPKG_ROOT: ${{ github.workspace }}/vcpkg
  VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/.vcpkg-cache

jobs:
  # ===== 多平台构建 =====
  build:
    name: Build (${{ matrix.os }}, ${{ matrix.compiler }})
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-22.04
            compiler: gcc-12
            cc: gcc-12
            cxx: g++-12
          - os: ubuntu-22.04
            compiler: clang-16
            cc: clang-16
            cxx: clang++-16
          - os: windows-2022
            compiler: msvc
          - os: macos-13
            compiler: clang

    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: 缓存 vcpkg
        uses: actions/cache@v4
        with:
          path: |
            ${{ env.VCPKG_DEFAULT_BINARY_CACHE }}
            ${{ env.VCPKG_ROOT }}
          key: vcpkg-${{ matrix.os }}-${{ hashFiles('vcpkg.json') }}

      - name: 安装 vcpkg
        run: |
          git clone https://github.com/microsoft/vcpkg.git $VCPKG_ROOT
          $VCPKG_ROOT/bootstrap-vcpkg.sh -disableMetrics
        if: runner.os != 'Windows'

      - name: 配置(Linux/macOS)
        if: runner.os != 'Windows'
        env:
          CC: ${{ matrix.cc }}
          CXX: ${{ matrix.cxx }}
        run: |
          cmake -B build \
            -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake \
            -DCMAKE_BUILD_TYPE=Release \
            -G Ninja

      - name: 构建
        run: cmake --build build --parallel

      - name: 测试
        run: ctest --test-dir build --output-on-failure --parallel 4

  # ===== Sanitizers =====
  sanitizers:
    name: Sanitizers
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - name: 安装工具
        run: sudo apt-get install -y cmake ninja-build clang-16

      - name: 构建(ASan + UBSan)
        env:
          CC: clang-16
          CXX: clang++-16
        run: |
          cmake -B build-asan \
            -DCMAKE_BUILD_TYPE=Debug \
            -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -g" \
            -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined" \
            -G Ninja
          cmake --build build-asan

      - name: 运行测试(ASan)
        env:
          ASAN_OPTIONS: detect_leaks=1:abort_on_error=1
          UBSAN_OPTIONS: print_stacktrace=1:abort_on_error=1
        run: ctest --test-dir build-asan --output-on-failure

      - name: 构建(TSan)
        env:
          CC: clang-16
          CXX: clang++-16
        run: |
          cmake -B build-tsan \
            -DCMAKE_BUILD_TYPE=Debug \
            -DCMAKE_CXX_FLAGS="-fsanitize=thread -g" \
            -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=thread" \
            -G Ninja
          cmake --build build-tsan

      - name: 运行测试(TSan)
        run: ctest --test-dir build-tsan --output-on-failure

  # ===== 静态分析 =====
  static-analysis:
    name: Static Analysis
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - name: 安装工具
        run: sudo apt-get install -y cmake ninja-build clang-tidy-16

      - name: 生成 compile_commands.json
        run: |
          cmake -B build \
            -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
            -DCMAKE_BUILD_TYPE=Debug \
            -G Ninja
          cmake --build build

      - name: 运行 Clang-Tidy
        run: |
          run-clang-tidy-16 -p build -j$(nproc) \
            -header-filter='(src|include)/.*' \
            2>&1 | tee clang-tidy.log
          ! grep -q "warning:" clang-tidy.log

  # ===== 代码格式检查 =====
  format:
    name: Code Format
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4
      - name: 检查格式
        run: |
          find src include -name "*.cpp" -o -name "*.h" | \
            xargs clang-format --dry-run --Werror

  # ===== Docker 发布 =====
  docker:
    name: Docker Build & Push
    runs-on: ubuntu-22.04
    needs: [build, sanitizers]
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4

      - name: 登录 Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}

      - name: 构建并推送
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            myorg/myapp:latest
            myorg/myapp:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

性能回归检测

yaml
  benchmark:
    name: Performance Benchmark
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - name: 构建 Benchmark
        run: |
          cmake -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_BENCHMARKS=ON
          cmake --build build

      - name: 运行 Benchmark
        run: |
          ./build/benchmarks/bench \
            --benchmark_out=benchmark_results.json \
            --benchmark_out_format=json

      - name: 存储结果
        uses: benchmark-action/github-action-benchmark@v1
        with:
          tool: 'googlecpp'
          output-file-path: benchmark_results.json
          github-token: ${{ secrets.GITHUB_TOKEN }}
          auto-push: true
          alert-threshold: '120%'  # 性能下降 20% 时报警
          comment-on-alert: true
          fail-on-alert: true

关键认知

C++ CI 的核心是多平台 + Sanitizers + 静态分析三位一体。vcpkg 缓存(actions/cache)避免每次重新编译依赖,是 CI 速度的关键。Sanitizers 在 CI 中运行,能在合并前发现内存问题。性能基准测试防止性能回归。

系统学习 C++ 生态,深入底层架构