CI/CD Integration¶
This guide covers the Nexus Embedded Platform’s CI/CD system, including the optimized GitHub Actions workflows and integration with other CI/CD platforms.
Overview¶
The Nexus platform provides a comprehensive, modular CI/CD system with:
Intelligent Triggering: Path-based filtering and smart scheduling
Modular Design: Reusable workflows and composite actions
Multi-Platform Builds: Windows, Linux, macOS, and ARM cross-compilation
Quality Assurance: Code coverage, static analysis, sanitizers, and MISRA compliance
Performance Optimization: Build caching, parallel execution, and smart dependencies
Complete Documentation: Automated Doxygen and Sphinx documentation with i18n support
System Architecture¶
The Nexus CI/CD system uses a modular architecture:
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
Optimization Results¶
The optimized CI/CD system achieves:
55% reduction in code size (from ~2000 to ~900 lines)
40% faster build times (from 25 to 15 minutes)
85% cache hit rate (up from 60%)
140% more parallel tasks (from 3-5 to 8-12)
GitHub Actions (Recommended)¶
The Nexus project uses an optimized GitHub Actions setup with modular workflows.
Main CI Workflow¶
The main workflow (.github/workflows/ci.yml) orchestrates all CI tasks:
Main CI Workflow¶
The main workflow (.github/workflows/ci.yml) orchestrates all CI tasks:
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
Build Matrix Workflow¶
The build matrix workflow (.github/workflows/build-matrix.yml) handles multi-platform builds:
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
Quality Checks Workflow¶
The quality checks workflow (.github/workflows/quality-checks.yml) ensures code quality:
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/
Documentation Workflow¶
The documentation workflow (.github/workflows/docs-build.yml) builds and deploys documentation:
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
Composite Action¶
The setup-build composite action (.github/actions/setup-build/action.yml) encapsulates environment setup:
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 }}
Release Workflow¶
The release workflow (.github/workflows/release.yml) automates releases:
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/*
Performance and Security Workflows¶
Additional workflows for performance testing and security scanning:
Performance Testing (.github/workflows/performance.yml):
Runs weekly on Monday
Performance benchmarks
Memory profiling with Valgrind
Code size analysis for ARM targets
Security Scanning (.github/workflows/security.yml):
Runs weekly on Sunday
Dependency scanning with Safety
CodeQL analysis for C/C++ and Python
Secret scanning with TruffleHog
License compliance checking
Using CMake Presets¶
The Nexus CI/CD system uses CMake Presets for consistent configuration:
# Configure
cmake --preset linux-gcc-release
# Build
cmake --build --preset linux-gcc-release --parallel
# Test
ctest --preset linux-gcc-release --output-on-failure
Available presets:
windows-msvc-debug/windows-msvc-releasewindows-gcc-debug/windows-gcc-releaselinux-gcc-debug/linux-gcc-releaselinux-gcc-coverage(with coverage enabled)linux-clang-debug/linux-clang-releasemacos-clang-debug/macos-clang-releasecross-arm-debug/cross-arm-release
Local Development¶
Run CI checks locally before pushing:
Format Check:
find hal osal framework -name '*.c' -o -name '*.h' | xargs clang-format -i
Build and Test:
cmake --preset linux-gcc-debug
cmake --build --preset linux-gcc-debug
ctest --preset linux-gcc-debug
Coverage Analysis:
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
Static Analysis:
# 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/
Complexity Analysis:
pip install lizard
lizard hal/ osal/ framework/ -l c -C 15 -L 100
Other CI/CD Platforms¶
While GitHub Actions is recommended, Nexus can integrate with other platforms.
GitLab CI¶
Basic .gitlab-ci.yml configuration:
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¶
Basic Jenkinsfile configuration:
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¶
Basic azure-pipelines.yml configuration:
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'
Best Practices¶
Caching Strategy¶
GitHub Actions:
- name: Cache Build
uses: actions/cache@v4
with:
path: |
build
~/.cache/ccache
key: ${{ runner.os }}-${{ matrix.preset }}-${{ hashFiles('**/CMakeLists.txt') }}
Benefits:
85% cache hit rate
40% faster builds
Reduced CI costs
Parallel Execution¶
Matrix Strategy:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
preset: [debug, release]
Benefits:
8-12 parallel tasks
Faster feedback
Better resource utilization
Artifact Management¶
Upload Artifacts:
- uses: actions/upload-artifact@v4
with:
name: build-artifacts
path: |
build/*/bin/*
build/*/lib/*
retention-days: 7
Best Practices:
Only upload necessary artifacts
Set appropriate retention periods
Use compression for large files
Quality Gates¶
Coverage Threshold:
- 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
Code Quality:
Format check must pass
No critical static analysis issues
Complexity within limits (CCN < 15)
MISRA compliance for safety-critical code
Troubleshooting¶
Common Issues¶
1. Submodule Checkout Failure
- uses: actions/checkout@v4
with:
submodules: recursive
token: ${{ secrets.GITHUB_TOKEN }}
2. Build Cache Corruption
# Clear cache and rebuild
rm -rf build ~/.cache/ccache
cmake --preset linux-gcc-release
cmake --build --preset linux-gcc-release
3. Test Timeout
- run: ctest --preset linux-gcc-release --timeout 600
4. Coverage Upload Failure
# Verify coverage file
ls -la coverage.info
lcov --list coverage.info
5. ARM Toolchain Issues
# Verify toolchain
arm-none-eabi-gcc --version
# Check PATH
echo $PATH | grep arm-none-eabi
Performance Optimization¶
Build Time Optimization:
Use ccache for compilation caching
Enable parallel builds (
--parallel)Use Ninja generator for faster builds
Cache CMake configuration
CI Cost Optimization:
Use path filters to skip unnecessary builds
Set appropriate artifact retention periods
Use concurrency control to cancel outdated runs
Schedule heavy jobs (performance, security) weekly
Monitoring and Metrics¶
Key Metrics:
Build success rate: > 95%
Average build time: < 20 minutes
Cache hit rate: > 80%
Test pass rate: > 99%
Coverage: > 80%
Monitoring Tools:
GitHub Actions dashboard
Codecov for coverage trends
Custom metrics in workflow summaries
See Also¶
Build System - Build system documentation
Testing - Testing guide
Coverage Analysis Workflow - Coverage analysis
Static Analysis - Static analysis tools
Release Process - Release process