CI/CD 集成¶
本指南介绍 Nexus 嵌入式平台的 CI/CD 系统,包括优化后的 GitHub Actions 工作流以及与其他 CI/CD 平台的集成。
概述¶
Nexus 平台提供了一个全面的模块化 CI/CD 系统,具有:
智能触发:基于路径的过滤和智能调度
模块化设计:可复用的工作流和组合操作
多平台构建:Windows、Linux、macOS 和 ARM 交叉编译
质量保证:代码覆盖率、静态分析、Sanitizer 和 MISRA 合规性
性能优化:构建缓存、并行执行和智能依赖
完整文档:自动化的 Doxygen 和 Sphinx 文档,支持国际化
系统架构¶
Nexus CI/CD 系统采用模块化架构:
ci.yml (Main Orchestrator)
↓
Smart Change Detection
↓
Trigger Sub-Workflows
├─► build-matrix.yml (Build & Test)
│ ├─ Multi-platform builds
│ ├─ Coverage analysis
│ └─ Sanitizer tests
│
├─► quality-checks.yml (Code Quality)
│ ├─ Format checking
│ ├─ Static analysis
│ ├─ Complexity analysis
│ └─ MISRA compliance
│
└─► docs-build.yml (Documentation)
├─ Doxygen API docs
├─ Sphinx user docs (EN/CN)
└─ GitHub Pages deployment
优化成果¶
优化后的 CI/CD 系统实现了:
GitHub Actions(推荐)¶
Nexus 项目使用优化的 GitHub Actions 设置,采用模块化工作流。
主 CI 工作流¶
主工作流(.github/workflows/ci.yml)协调所有 CI 任务:
主 CI 工作流¶
主工作流(.github/workflows/ci.yml)协调所有 CI 任务:
name: CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
workflow_dispatch:
schedule:
- cron: '0 2 * * *'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
changes:
name: Detect Changes
runs-on: ubuntu-latest
outputs:
code: ${{ steps.filter.outputs.code }}
docs: ${{ steps.filter.outputs.docs }}
workflows: ${{ steps.filter.outputs.workflows }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
code:
- 'hal/**'
- 'osal/**'
- 'framework/**'
- '**/CMakeLists.txt'
docs:
- 'docs/**'
- '**.md'
workflows:
- '.github/workflows/**'
build-test:
name: Build & Test
needs: changes
if: needs.changes.outputs.code == 'true'
uses: ./.github/workflows/build-matrix.yml
secrets: inherit
code-quality:
name: Code Quality
needs: changes
if: needs.changes.outputs.code == 'true'
uses: ./.github/workflows/quality-checks.yml
docs:
name: Documentation
needs: changes
if: needs.changes.outputs.docs == 'true'
uses: ./.github/workflows/docs-build.yml
secrets: inherit
构建矩阵工作流¶
构建矩阵工作流(.github/workflows/build-matrix.yml)处理多平台构建:
name: Build Matrix
on:
workflow_call:
secrets:
CODECOV_TOKEN:
required: false
jobs:
matrix-build:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: Windows MSVC Release
os: windows-latest
preset: windows-msvc-release
upload_artifacts: true
- name: Linux GCC Release
os: ubuntu-latest
preset: linux-gcc-release
upload_artifacts: true
- name: macOS Clang Release
os: macos-latest
preset: macos-clang-release
upload_artifacts: true
- name: ARM Cortex-M4 Release
os: ubuntu-latest
preset: cross-arm-release
upload_artifacts: true
is_arm: true
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Build Environment
uses: ./.github/actions/setup-build
with:
os: ${{ matrix.os }}
preset: ${{ matrix.preset }}
- name: Configure
run: cmake --preset ${{ matrix.preset }}
- name: Build
run: cmake --build --preset ${{ matrix.preset }} --parallel
- name: Test
if: ${{ !matrix.is_arm }}
run: ctest --preset ${{ matrix.preset }} --output-on-failure
coverage:
name: Coverage Analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Build Environment
uses: ./.github/actions/setup-build
with:
os: ubuntu-latest
preset: linux-gcc-coverage
- name: Configure
run: cmake --preset linux-gcc-coverage
- name: Build
run: cmake --build --preset linux-gcc-coverage --parallel
- name: Test
run: ctest --preset linux-gcc-coverage --output-on-failure
- name: Generate Coverage
run: |
lcov --capture --directory . --output-file coverage.info
lcov --remove coverage.info '/usr/*' '*/tests/*' '*/ext/*' \
--output-file coverage.info
- name: Upload to Codecov
uses: codecov/codecov-action@v4
with:
files: ./coverage.info
flags: unittests
sanitizer:
name: Sanitizer - ${{ matrix.sanitizer }}
runs-on: ubuntu-latest
strategy:
matrix:
sanitizer: [address, undefined, thread]
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Build Environment
uses: ./.github/actions/setup-build
with:
os: ubuntu-latest
preset: linux-gcc-debug
- name: Configure with Sanitizer
run: |
SANITIZER_FLAG=""
case "${{ matrix.sanitizer }}" in
address) SANITIZER_FLAG="-fsanitize=address" ;;
undefined) SANITIZER_FLAG="-fsanitize=undefined" ;;
thread) SANITIZER_FLAG="-fsanitize=thread" ;;
esac
cmake -B build -DCMAKE_BUILD_TYPE=Debug \
-DNEXUS_PLATFORM=native -DNEXUS_BUILD_TESTS=ON \
-DCMAKE_C_FLAGS="$SANITIZER_FLAG"
- name: Build
run: cmake --build build --parallel
- name: Test
run: ctest --test-dir build --output-on-failure
质量检查工作流¶
质量检查工作流(.github/workflows/quality-checks.yml)确保代码质量:
name: Quality Checks
on:
workflow_call:
jobs:
format-check:
name: Format Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check clang-format
run: |
sudo apt-get install -y clang-format-14
find hal osal framework \
\( -name '*.c' -o -name '*.h' \) \
-exec clang-format-14 --dry-run --Werror {} +
static-analysis:
name: Static Analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Build Environment
uses: ./.github/actions/setup-build
with:
os: ubuntu-latest
preset: linux-clang-debug
- name: Configure
run: cmake --preset linux-clang-debug
- name: Run clang-tidy
run: |
run-clang-tidy-14 -p build/linux-clang-debug \
'hal/.*|osal/.*|framework/.*'
- name: Run cppcheck
run: |
sudo apt-get install -y cppcheck
cppcheck --enable=all --inconclusive \
-I hal/include -I osal/include -I framework/include \
hal/ osal/ framework/
complexity:
name: Complexity Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run lizard
run: |
pip install lizard
lizard hal/ osal/ framework/ -l c -C 15 -L 100
misra:
name: MISRA Compliance
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run MISRA Check
run: |
sudo apt-get install -y cppcheck
cppcheck --addon=misra \
-I hal/include -I osal/include -I framework/include \
hal/ osal/ framework/
文档工作流¶
文档工作流(.github/workflows/docs-build.yml)构建和部署文档:
name: Documentation Build
on:
workflow_call:
permissions:
contents: read
pages: write
id-token: write
jobs:
build:
name: Build Docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- name: Install Dependencies
run: |
sudo apt-get install -y doxygen graphviz
pip install -r docs/sphinx/requirements.txt
- name: Build Doxygen
run: doxygen Doxyfile
- name: Build Sphinx (English)
working-directory: docs/sphinx
run: sphinx-build -b html . _build/html/en
- name: Build Sphinx (Chinese)
working-directory: docs/sphinx
run: sphinx-build -b html -D language=zh_CN . _build/html/zh_CN
- name: Prepare Pages
run: |
mkdir -p public
cp -r docs/api/html public/api
cp -r docs/sphinx/_build/html/* public/
- name: Upload Pages Artifact
uses: actions/upload-pages-artifact@v3
with:
path: public
deploy:
name: Deploy to Pages
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy
id: deployment
uses: actions/deploy-pages@v4
组合操作¶
setup-build 组合操作(.github/actions/setup-build/action.yml)封装了环境设置:
name: Setup Build Environment
description: Setup build tools and dependencies for Nexus
inputs:
os:
description: 'Operating system'
required: true
preset:
description: 'CMake preset name'
required: true
runs:
using: composite
steps:
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- name: Install Python Dependencies
shell: bash
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Install Build Tools (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y cmake ninja-build ccache
if [[ "${{ inputs.preset }}" == *"clang"* ]]; then
sudo apt-get install -y clang-14 clang-tidy-14
fi
if [[ "${{ inputs.preset }}" == *"coverage"* ]]; then
sudo apt-get install -y lcov
fi
if [[ "${{ inputs.preset }}" == *"arm"* ]]; then
sudo apt-get install -y gcc-arm-none-eabi
fi
- name: Setup ccache (Linux)
if: runner.os == 'Linux'
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ inputs.preset }}
发布工作流¶
发布工作流(.github/workflows/release.yml)自动化发布流程:
name: Release
on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g., v1.0.0)'
required: true
jobs:
create-release:
name: Create Release
runs-on: ubuntu-latest
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
version: ${{ steps.get_version.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get version
id: get_version
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT
else
echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
fi
- name: Create Release
id: create_release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.get_version.outputs.version }}
name: Release ${{ steps.get_version.outputs.version }}
build-release:
name: Build ${{ matrix.name }}
needs: create-release
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- name: Windows MSVC
os: windows-latest
preset: windows-msvc-release
- name: Linux GCC
os: ubuntu-latest
preset: linux-gcc-release
- name: macOS Clang
os: macos-latest
preset: macos-clang-release
- name: ARM Cortex-M4
os: ubuntu-latest
preset: cross-arm-release
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Build Environment
uses: ./.github/actions/setup-build
with:
os: ${{ matrix.os }}
preset: ${{ matrix.preset }}
- name: Configure
run: cmake --preset ${{ matrix.preset }}
- name: Build
run: cmake --build --preset ${{ matrix.preset }} --parallel
- name: Package
run: |
mkdir -p release/${{ matrix.name }}
cp -r build/${{ matrix.preset }}/bin/* release/${{ matrix.name }}/
cp README.md LICENSE release/${{ matrix.name }}/
- name: Upload to Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ needs.create-release.outputs.version }}
files: release/*
性能和安全工作流¶
用于性能测试和安全扫描的附加工作流:
**性能测试**(.github/workflows/performance.yml):
每周一运行
性能基准测试
使用 Valgrind 进行内存分析
ARM 目标的代码大小分析
**安全扫描**(.github/workflows/security.yml):
每周日运行
使用 Safety 进行依赖扫描
C/C++ 和 Python 的 CodeQL 分析
使用 TruffleHog 进行密钥扫描
许可证合规性检查
使用 CMake Presets¶
Nexus CI/CD 系统使用 CMake Presets 进行一致的配置:
# Configure
cmake --preset linux-gcc-release
# Build
cmake --build --preset linux-gcc-release --parallel
# Test
ctest --preset linux-gcc-release --output-on-failure
可用的 presets:
windows-msvc-debug/windows-msvc-releasewindows-gcc-debug/windows-gcc-releaselinux-gcc-debug/linux-gcc-release``linux-gcc-coverage``(启用覆盖率)
linux-clang-debug/linux-clang-releasemacos-clang-debug/macos-clang-releasecross-arm-debug/cross-arm-release
本地开发¶
在推送之前在本地运行 CI 检查:
格式检查:
find hal osal framework -name '*.c' -o -name '*.h' | xargs clang-format -i
构建和测试:
cmake --preset linux-gcc-debug
cmake --build --preset linux-gcc-debug
ctest --preset linux-gcc-debug
覆盖率分析:
cmake --preset linux-gcc-coverage
cmake --build --preset linux-gcc-coverage
ctest --preset linux-gcc-coverage
# Generate report
lcov --capture --directory . --output-file coverage.info
lcov --remove coverage.info '/usr/*' '*/tests/*' --output-file coverage.info
genhtml coverage.info --output-directory coverage_html
静态分析:
# clang-tidy
cmake --preset linux-clang-debug
run-clang-tidy -p build/linux-clang-debug
# cppcheck
cppcheck --enable=all -I hal/include -I osal/include hal/ osal/
复杂度分析:
pip install lizard
lizard hal/ osal/ framework/ -l c -C 15 -L 100
其他 CI/CD 平台¶
虽然推荐使用 GitHub Actions,但 Nexus 也可以与其他平台集成。
GitLab CI¶
基本的 .gitlab-ci.yml 配置:
stages:
- build
- test
- deploy
variables:
GIT_SUBMODULE_STRATEGY: recursive
build:linux:
stage: build
image: ubuntu:22.04
before_script:
- apt-get update && apt-get install -y cmake ninja-build gcc g++
script:
- cmake --preset linux-gcc-release
- cmake --build --preset linux-gcc-release
artifacts:
paths:
- build/
expire_in: 1 hour
test:
stage: test
image: ubuntu:22.04
dependencies:
- build:linux
script:
- ctest --preset linux-gcc-release --output-on-failure
Jenkins¶
基本的 Jenkinsfile 配置:
pipeline {
agent any
stages {
stage('Checkout') {
steps {
checkout scm
sh 'git submodule update --init --recursive'
}
}
stage('Build') {
steps {
sh '''
cmake --preset linux-gcc-release
cmake --build --preset linux-gcc-release --parallel
'''
}
}
stage('Test') {
steps {
sh 'ctest --preset linux-gcc-release --output-on-failure'
}
}
}
post {
always {
archiveArtifacts artifacts: 'build/**/*', allowEmptyArchive: true
}
}
}
Azure DevOps¶
基本的 azure-pipelines.yml 配置:
trigger:
branches:
include:
- main
- develop
pool:
vmImage: 'ubuntu-latest'
steps:
- checkout: self
submodules: true
- script: |
cmake --preset linux-gcc-release
cmake --build --preset linux-gcc-release --parallel
displayName: 'Build'
- script: |
ctest --preset linux-gcc-release --output-on-failure
displayName: 'Test'
最佳实践¶
缓存策略¶
GitHub Actions:
- name: Cache Build
uses: actions/cache@v4
with:
path: |
build
~/.cache/ccache
key: ${{ runner.os }}-${{ matrix.preset }}-${{ hashFiles('**/CMakeLists.txt') }}
优势:
85% 缓存命中率
构建速度提升 40%
降低 CI 成本
并行执行¶
矩阵策略:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
preset: [debug, release]
优势:
8-12 个并行任务
更快的反馈
更好的资源利用
产物管理¶
上传产物:
- uses: actions/upload-artifact@v4
with:
name: build-artifacts
path: |
build/*/bin/*
build/*/lib/*
retention-days: 7
最佳实践:
只上传必要的产物
设置适当的保留期限
对大文件使用压缩
质量门禁¶
覆盖率阈值:
- name: Check Coverage
run: |
COVERAGE=$(lcov --summary coverage.info | grep lines | awk '{print $2}')
if (( $(echo "$COVERAGE < 80.0" | bc -l) )); then
echo "Coverage $COVERAGE% below threshold"
exit 1
fi
代码质量:
格式检查必须通过
无严重的静态分析问题
复杂度在限制范围内(CCN < 15)
安全关键代码的 MISRA 合规性
故障排除¶
常见问题¶
1. 子模块检出失败
- uses: actions/checkout@v4
with:
submodules: recursive
token: ${{ secrets.GITHUB_TOKEN }}
2. 构建缓存损坏
# Clear cache and rebuild
rm -rf build ~/.cache/ccache
cmake --preset linux-gcc-release
cmake --build --preset linux-gcc-release
3. 测试超时
- run: ctest --preset linux-gcc-release --timeout 600
4. 覆盖率上传失败
# Verify coverage file
ls -la coverage.info
lcov --list coverage.info
5. ARM 工具链问题
# Verify toolchain
arm-none-eabi-gcc --version
# Check PATH
echo $PATH | grep arm-none-eabi
性能优化¶
构建时间优化:
使用 ccache 进行编译缓存
启用并行构建(
--parallel)使用 Ninja 生成器加快构建速度
缓存 CMake 配置
CI 成本优化:
使用路径过滤器跳过不必要的构建
设置适当的产物保留期限
使用并发控制取消过时的运行
每周安排重型任务(性能、安全)
监控和指标¶
关键指标:
构建成功率:> 95%
平均构建时间:< 20 分钟
缓存命中率:> 80%
测试通过率:> 99%
覆盖率:> 80%
监控工具:
GitHub Actions 仪表板
Codecov 用于覆盖率趋势
工作流摘要中的自定义指标
另请参阅¶
Build System - 构建系统文档
测试 - 测试指南
Coverage Analysis Workflow - 覆盖率分析
Static Analysis - 静态分析工具
Release Process - 发布流程