Skip to content

docs: announce v1.x on master and v0.x maintenance branch (#361) #1233

docs: announce v1.x on master and v0.x maintenance branch (#361)

docs: announce v1.x on master and v0.x maintenance branch (#361) #1233

Workflow file for this run

name: Build and Test
on:
push:
branches:
- master # tagged latest
- 'release/**' # release branches
- 'hotfix/**' # hotfix branches
- 'dev-publish/**' # development branches that publish packages
tags:
- v* # semver release
pull_request: # runs tests for PRs to master and to long-lived integration branches
branches:
- master
- version1 # v1.0 integration branch (PR #151); stacked PRs land here first
- v0.x # v0.x maintenance branch
workflow_dispatch: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
NAME: kth-mono
CONAN_REMOTE: kth
CONAN_REMOTE_URL: https://packages.kth.cash/api/
# Static analysis flags
SKIP_CLANG_FORMAT: true # Set to false to enable clang-format checks
SKIP_CLANG_TIDY: true # Set to false to enable clang-tidy analysis
SKIP_CPPCHECK: true # Set to false to enable cppcheck analysis
SKIP_IWYU: false # Set to false to enable include-what-you-use analysis
# Build strategy:
#
# ALL BRANCHES:
# - Sanitizer builds: Always run WITH sanitizers for quality assurance (never uploaded)
#
# RELEASE BRANCHES ONLY (release/hotfix/dev-publish):
# - Relase builds: Clean binaries WITHOUT sanitizers (uploaded to registry)
#
# This ensures:
# • Development branches: Only sanitizer builds (1 build per platform)
# • Release branches: Sanitizer builds + release builds (2 builds per platform)
# • Release packages: Always clean (no sanitizer instrumentation)
#
# NOTE: AddressSanitizer and ThreadSanitizer are mutually exclusive on Clang (macOS)
jobs:
debug:
runs-on: ubuntu-latest
outputs:
permitted: ${{ steps.check.outputs.permitted }}
steps:
- name: 🐛 Debug Check Job
run: |
echo "Event name: ${{ github.event_name }}"
echo "Ref: ${{ github.ref }}"
echo "Condition result: ${{ github.event_name == 'pull_request' || startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/master' }}"
check:
if: github.event_name == 'push' ||
(github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'release/') &&
!startsWith(github.head_ref, 'hotfix/') &&
!startsWith(github.head_ref, 'docs/') &&
!startsWith(github.head_ref, 'style/') &&
!startsWith(github.head_ref, 'chore/') &&
!startsWith(github.head_ref, 'noci/'))
runs-on: ubuntu-latest
outputs:
permitted: ${{ steps.check.outputs.permitted }}
steps:
- name: 🐛 Debug Check Job
run: |
echo "Event name: ${{ github.event_name }}"
echo "Ref: ${{ github.ref }}"
echo "Condition result: ${{ github.event_name == 'pull_request' || startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/dev-publish') }}"
- name: 🔐 Check permissions
id: check
continue-on-error: true
uses: prince-chrismc/check-actor-permissions-action@d504e74ba31658f4cdf4fcfeb509d4c09736d88e # v3.0.2
with:
permission: write
setup:
if: github.event_name == 'push' ||
(github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'release/') &&
!startsWith(github.head_ref, 'hotfix/') &&
!startsWith(github.head_ref, 'docs/') &&
!startsWith(github.head_ref, 'style/') &&
!startsWith(github.head_ref, 'chore/') &&
!startsWith(github.head_ref, 'noci/'))
runs-on: ubuntu-latest
outputs:
build-version: ${{ steps.version.outputs.build-version }}
steps:
- name: 📥 Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
submodules: true
fetch-depth: 0 # Required due to the way Git works, without it this action won't be able to find any or the correct tags
- name: 🔧 Determine version
id: version
uses: ./ci_utils/.github/actions/determine-version
with:
github-ref: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref }}
run-number: ${{ github.run_number }}
- name: 📊 Build configuration summary
run: |
echo "## 🚀 Build Configuration" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 📦 Version" >> $GITHUB_STEP_SUMMARY
echo "**Version:** \`${{ steps.version.outputs.build-version }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🔀 Source" >> $GITHUB_STEP_SUMMARY
echo "**Event:** ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY
if [ "${{ github.event_name }}" = "pull_request" ]; then
echo "**Branch:** ${{ github.head_ref }}" >> $GITHUB_STEP_SUMMARY
echo "**Base:** ${{ github.base_ref }}" >> $GITHUB_STEP_SUMMARY
echo "**PR:** #${{ github.event.pull_request.number }}" >> $GITHUB_STEP_SUMMARY
else
echo "**Ref:** ${{ github.ref }}" >> $GITHUB_STEP_SUMMARY
fi
echo "**Commit:** \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🔍 Static Analysis" >> $GITHUB_STEP_SUMMARY
echo "- **clang-format:** ${{ env.SKIP_CLANG_FORMAT == 'true' && '⏭️ Skipped' || '✅ Enabled' }}" >> $GITHUB_STEP_SUMMARY
echo "- **clang-tidy:** ${{ env.SKIP_CLANG_TIDY == 'true' && '⏭️ Skipped' || '✅ Enabled' }}" >> $GITHUB_STEP_SUMMARY
echo "- **cppcheck:** ${{ env.SKIP_CPPCHECK == 'true' && '⏭️ Skipped' || '✅ Enabled' }}" >> $GITHUB_STEP_SUMMARY
echo "- **IWYU:** ${{ env.SKIP_IWYU == 'true' && '⏭️ Skipped' || '✅ Enabled' }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🏗️ Build Strategy" >> $GITHUB_STEP_SUMMARY
if [[ "${{ github.ref }}" == refs/heads/release/* ]] || [[ "${{ github.ref }}" == refs/heads/hotfix/* ]] || [[ "${{ github.ref }}" == refs/heads/dev-publish/* ]] || [[ "${{ github.ref }}" == refs/tags/* ]]; then
echo "**Type:** 🚀 Release builds + Sanitizer builds" >> $GITHUB_STEP_SUMMARY
echo "**Upload:** ✅ Packages will be uploaded to Conan registry" >> $GITHUB_STEP_SUMMARY
else
echo "**Type:** 🔨 Development builds (Sanitizer builds only)" >> $GITHUB_STEP_SUMMARY
echo "**Upload:** ⏭️ Packages will not be uploaded" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🎯 Build Matrix" >> $GITHUB_STEP_SUMMARY
echo "Builds will run on multiple platforms with different sanitizer configurations:" >> $GITHUB_STEP_SUMMARY
echo "- Linux (GCC 14) - AddressSanitizer + UndefinedBehaviorSanitizer" >> $GITHUB_STEP_SUMMARY
echo "- macOS (Apple Clang 15) - AddressSanitizer + UndefinedBehaviorSanitizer" >> $GITHUB_STEP_SUMMARY
echo "- macOS (Apple Clang 15) - ThreadSanitizer" >> $GITHUB_STEP_SUMMARY
echo "- WebAssembly (Emscripten)" >> $GITHUB_STEP_SUMMARY
# build-base-docker-image:
# name: Builds Alpine Docker image
# runs-on: ubuntu-latest
# outputs:
# # name: docker.pkg.github.com/${{ github.repository }}/alpine-image:${{ steps.version.outputs.version }}
# name: docker.pkg.github.com/k-nuth/kth/alpine-image:${{ steps.version.outputs.version }}
# env:
# # name: docker.pkg.github.com/${{ github.repository }}/alpine-image
# name: docker.pkg.github.com/k-nuth/kth/alpine-image
# steps:
# - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
# with:
# submodules: true
# - id: version
# run: echo "version=${{ hashFiles('./ci_utils/Dockerfile.build') }}" >> $GITHUB_OUTPUT
# - uses: docker/login-action@v2
# with:
# registry: docker.pkg.github.com
# username: ${{ github.repository_owner }}
# password: ${{ secrets.GITHUB_TOKEN }}
# - id: check
# name: check existence
# run: |
# docker pull ${{ env.name }}:${{ steps.version.outputs.version }} > /dev/null && echo "exists=true" >> $GITHUB_OUTPUT || echo "exists=false" >> $GITHUB_OUTPUT
# - if: ${{ steps.check.outputs.exists == 'false' }}
# run: docker build . --file ./ci_utils/Dockerfile.build --tag ${{ env.name }}:${{ steps.version.outputs.version }}
# - if: ${{ steps.check.outputs.exists == 'false' }}
# run: docker push ${{ env.name }}:${{ steps.version.outputs.version }}
generate-matrix:
if: github.event_name == 'push' ||
(github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'release/') &&
!startsWith(github.head_ref, 'hotfix/') &&
!startsWith(github.head_ref, 'docs/') &&
!startsWith(github.head_ref, 'style/') &&
!startsWith(github.head_ref, 'chore/') &&
!startsWith(github.head_ref, 'noci/'))
name: Generate Job Matrix
runs-on: ubuntu-22.04
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: 🐛 Debug Info
run: |
echo "Event name: ${{ github.event_name }}"
echo "Ref: ${{ github.ref }}"
echo "Head ref: ${{ github.head_ref }}"
echo "Base ref: ${{ github.base_ref }}"
- name: 📥 Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
submodules: true
- name: 🧮 Generate Job Matrix
id: set-matrix
run: |
MATRIX=$(cat ./ci_utils/.github/matrix.json)
echo "${MATRIX}"
echo "matrix=${MATRIX}" >> $GITHUB_OUTPUT
calc-deps-with-container:
needs: [setup, generate-matrix]
strategy:
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
name: ${{ matrix.config.name }}
uses: ./.github/workflows/calc-deps-with-container.yml
with:
if: ${{ matrix.config.compiler == 'GCC' }}
os: ${{ matrix.config.os }}
image: "kthnode/gcc${{ matrix.config.version }}${{ matrix.config.docker_suffix }}"
conan-remote: "kth"
build-version: ${{ needs.setup.outputs.build-version }}
secrets:
conan-user: ${{ secrets.CONAN_LOGIN_USERNAME }}
conan-password: ${{ secrets.CONAN_3_PASSWORD }}
calc-deps-without-container:
needs: [setup, generate-matrix]
strategy:
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
name: ${{ matrix.config.name }}
uses: ./.github/workflows/calc-deps-without-container.yml
with:
if: ${{ matrix.config.compiler != 'GCC' }}
os: ${{ matrix.config.os }}
conan-remote: "kth"
build-version: ${{ needs.setup.outputs.build-version }}
secrets:
conan-user: ${{ secrets.CONAN_LOGIN_USERNAME }}
conan-password: ${{ secrets.CONAN_3_PASSWORD }}
build-deps-with-container:
needs: [calc-deps-with-container]
strategy:
matrix: ${{ fromJson(needs.calc-deps-with-container.outputs.matrix) }}
name: ${{ matrix.config.name }}
uses: ./.github/workflows/build-deps-with-container.yml
with:
if: ${{ matrix.config.compiler == 'GCC' }}
os: ${{ matrix.config.os }}
image: "kthnode/gcc${{ matrix.config.version }}${{ matrix.config.docker_suffix }}"
reference: ${{ matrix.config.reference }}
context: ${{ matrix.config.context }}
conan-remote: "kth"
secrets:
conan-user: ${{ secrets.CONAN_LOGIN_USERNAME }}
conan-password: ${{ secrets.CONAN_3_PASSWORD }}
build-deps-without-container:
needs: [calc-deps-without-container]
strategy:
matrix: ${{ fromJson(needs.calc-deps-without-container.outputs.matrix) }}
name: ${{ matrix.config.name }}
uses: ./.github/workflows/build-deps-without-container.yml
with:
if: ${{ matrix.config.compiler != 'GCC' }}
os: ${{ matrix.config.os }}
reference: ${{ matrix.config.reference }}
context: ${{ matrix.config.context }}
conan-remote: "kth"
secrets:
conan-user: ${{ secrets.CONAN_LOGIN_USERNAME }}
conan-password: ${{ secrets.CONAN_3_PASSWORD }}
build-with-container:
needs: [setup, generate-matrix]
strategy:
fail-fast: false
matrix: ${{fromJson(needs.generate-matrix.outputs.matrix)}}
name: ${{ matrix.config.name }} (Build & Test)
uses: ./.github/workflows/build-with-container.yml
with:
if: ${{ matrix.config.compiler == 'GCC' }}
upload: false
os: ${{ matrix.config.os }}
image: "kthnode/gcc${{ matrix.config.version }}${{ matrix.config.docker_suffix }}"
conan-remote: "kth"
recipe-name: "kth"
compiler: ${{ matrix.config.compiler }}
compiler-version: ${{ matrix.config.version }}
build-version: "${{ needs.setup.outputs.build-version }}"
enable-asan: false
enable-ubsan: false
enable-tsan: false
skip-tests: false
secrets:
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_LOGIN_USERNAME }}
CONAN_PASSWORD: ${{ secrets.CONAN_3_PASSWORD }}
build-with-container-sanitizers:
needs: [setup, generate-matrix]
strategy:
fail-fast: false
matrix: ${{fromJson(needs.generate-matrix.outputs.matrix)}}
name: ${{ matrix.config.name }} (Sanitizers)
uses: ./.github/workflows/build-with-container.yml
with:
if: ${{ matrix.config.compiler == 'GCC' }}
upload: false
os: ${{ matrix.config.os }}
image: "kthnode/gcc${{ matrix.config.version }}${{ matrix.config.docker_suffix }}"
conan-remote: "kth"
recipe-name: "kth"
compiler: ${{ matrix.config.compiler }}
compiler-version: ${{ matrix.config.version }}
build-version: "${{ needs.setup.outputs.build-version }}"
enable-asan: true
enable-ubsan: true
enable-tsan: false # tsan is mutually exclusive with asan
skip-tests: false
secrets:
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_LOGIN_USERNAME }}
CONAN_PASSWORD: ${{ secrets.CONAN_3_PASSWORD }}
build-without-container:
needs: [setup, generate-matrix]
strategy:
fail-fast: false
matrix: ${{fromJson(needs.generate-matrix.outputs.matrix)}}
name: ${{ matrix.config.name }} (Build & Test)
uses: ./.github/workflows/build-without-container.yml
with:
if: ${{ matrix.config.compiler != 'GCC' }}
upload: false
os: ${{ matrix.config.os }}
conan-remote: "kth"
recipe-name: "kth"
compiler: ${{ matrix.config.compiler }}
compiler-version: ${{ matrix.config.version }}
build-version: "${{ needs.setup.outputs.build-version }}"
enable-asan: false # Disabled due to secp256k1 inline assembly conflicts
enable-ubsan: false # Disabled due to secp256k1 inline assembly conflicts
enable-tsan: false # Disabled due to secp256k1 inline assembly conflicts
skip-tests: false
secrets:
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_LOGIN_USERNAME }}
CONAN_PASSWORD: ${{ secrets.CONAN_3_PASSWORD }}
build-with-container-release:
needs: [setup, generate-matrix]
# Only run release builds when uploading (clean binaries for release branches)
if: ${{ (github.event_name == 'push' && (startsWith(github.ref, 'refs/heads/release') || startsWith(github.ref, 'refs/heads/hotfix') || startsWith(github.ref, 'refs/heads/dev-publish'))) || (github.event_name == 'pull_request' && (startsWith(github.head_ref, 'release/') || startsWith(github.head_ref, 'hotfix/') || startsWith(github.head_ref, 'dev-publish/'))) }}
strategy:
fail-fast: false
matrix: ${{fromJson(needs.generate-matrix.outputs.matrix)}}
name: ${{ matrix.config.name }} (Release)
uses: ./.github/workflows/build-with-container.yml
with:
if: ${{ matrix.config.compiler == 'GCC' }}
upload: true # Upload clean release builds
os: ${{ matrix.config.os }}
image: "kthnode/gcc${{ matrix.config.version }}${{ matrix.config.docker_suffix }}"
conan-remote: "kth"
recipe-name: "kth"
compiler: ${{ matrix.config.compiler }}
compiler-version: ${{ matrix.config.version }}
build-version: "${{ needs.setup.outputs.build-version }}"
enable-asan: false # Disabled for clean release builds
enable-ubsan: false # Disabled for clean release builds
enable-tsan: false # Disabled for clean release builds
skip-tests: false # Skip tests for clean release builds
secrets:
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_LOGIN_USERNAME }}
CONAN_PASSWORD: ${{ secrets.CONAN_3_PASSWORD }}
build-without-container-release:
needs: [setup, generate-matrix]
# Only run release builds when uploading (clean binaries for release branches)
if: ${{ (github.event_name == 'push' && (startsWith(github.ref, 'refs/heads/release') || startsWith(github.ref, 'refs/heads/hotfix') || startsWith(github.ref, 'refs/heads/dev-publish'))) || (github.event_name == 'pull_request' && (startsWith(github.head_ref, 'release/') || startsWith(github.head_ref, 'hotfix/') || startsWith(github.head_ref, 'dev-publish/'))) }}
strategy:
fail-fast: false
matrix: ${{fromJson(needs.generate-matrix.outputs.matrix)}}
name: ${{ matrix.config.name }} (Release)
uses: ./.github/workflows/build-without-container.yml
with:
if: ${{ matrix.config.compiler != 'GCC' }}
upload: true # Upload clean release builds
os: ${{ matrix.config.os }}
conan-remote: "kth"
recipe-name: "kth"
compiler: ${{ matrix.config.compiler }}
compiler-version: ${{ matrix.config.version }}
build-version: "${{ needs.setup.outputs.build-version }}"
enable-asan: false # Disabled for clean release builds
enable-ubsan: false # Disabled for clean release builds
enable-tsan: false # Disabled for clean release builds
skip-tests: false
secrets:
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_LOGIN_USERNAME }}
CONAN_PASSWORD: ${{ secrets.CONAN_3_PASSWORD }}
static-checks:
name: Static Checks
if: github.event_name == 'push' ||
(github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'release/') &&
!startsWith(github.head_ref, 'hotfix/') &&
!startsWith(github.head_ref, 'docs/') &&
!startsWith(github.head_ref, 'style/') &&
!startsWith(github.head_ref, 'chore/') &&
!startsWith(github.head_ref, 'noci/'))
runs-on: ubuntu-22.04
steps:
- name: 📥 Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
submodules: true
- name: 🔧 Install clang-format
if: env.SKIP_CLANG_FORMAT != 'true'
run: |
sudo apt-get update
sudo apt-get install -y clang-format-15
clang-format-15 --version
- name: ⏭️ Clang-format check disabled
if: env.SKIP_CLANG_FORMAT == 'true'
run: |
echo "⚠️ Clang-format check is currently disabled"
echo "Set SKIP_CLANG_FORMAT=false in workflow env to enable"
- name: 🎨 Check code formatting
if: env.SKIP_CLANG_FORMAT != 'true'
shell: bash
run: |
echo "Checking C++ code formatting with clang-format..."
# Find all C++ source files, avoiding broken pipe by using process substitution
find . \( -name "*.cpp" -o -name "*.hpp" -o -name "*.h" -o -name "*.c" \) \
-not -path "./build/*" \
-not -path "./cmake-build-*" \
-not -path "./.conan/*" \
-not -path "./third_party/*" \
-not -path "./ci_utils/*" > cpp_files_all.txt
# Take first 50 files to avoid overwhelming the CI
head -50 cpp_files_all.txt > cpp_files.txt
total_files=$(wc -l < cpp_files_all.txt)
check_files=$(wc -l < cpp_files.txt)
echo "Found $total_files C++ files total, checking first $check_files files"
# Check formatting and collect results
format_issues=0
while IFS= read -r file; do
if [ -f "$file" ]; then
if ! clang-format-15 --dry-run --Werror "$file" 2>/dev/null; then
echo "❌ Formatting issues in: $file"
echo "--- Expected format diff:"
clang-format-15 "$file" | diff -u "$file" - || true
echo ""
format_issues=$((format_issues + 1))
else
echo "✅ $file"
fi
fi
done < cpp_files.txt
# Cleanup
rm -f cpp_files_all.txt cpp_files.txt
if [ $format_issues -gt 0 ]; then
echo ""
echo "❌ Found $format_issues files with formatting issues"
echo "To fix, run: clang-format-15 -i <file>"
exit 1
else
echo ""
echo "✅ All checked files are properly formatted!"
fi
- name: 🔧 Install clang-tidy
if: env.SKIP_CLANG_TIDY != 'true'
run: |
sudo apt-get update
sudo apt-get install -y clang-tidy-15
clang-tidy-15 --version
- name: ⏭️ Clang-tidy analysis disabled
if: env.SKIP_CLANG_TIDY == 'true'
run: |
echo "⚠️ Clang-tidy analysis is currently disabled"
echo "Set SKIP_CLANG_TIDY=false in workflow env to enable"
- name: 🔍 Run clang-tidy analysis
if: env.SKIP_CLANG_TIDY != 'true'
shell: bash
run: |
echo "🔍 Running clang-tidy analysis..."
# Find all C++ source files
find . \( -name "*.cpp" -o -name "*.hpp" -o -name "*.h" -o -name "*.c" \) \
-not -path "./build/*" \
-not -path "./cmake-build-*" \
-not -path "./.conan/*" \
-not -path "./third_party/*" \
-not -path "./ci_utils/*" > cpp_files_all.txt
# Take first 20 files to avoid overwhelming CI
head -20 cpp_files_all.txt > cpp_files.txt
total_files=$(wc -l < cpp_files_all.txt)
check_files=$(wc -l < cpp_files.txt)
echo "Found $total_files C++ files total, analyzing first $check_files files"
# Run clang-tidy analysis
tidy_issues=0
while IFS= read -r file; do
if [ -f "$file" ]; then
echo "🔍 Analyzing: $file"
if ! clang-tidy-15 "$file" -- -std=c++17 2>/dev/null; then
echo "⚠️ Issues found in: $file"
tidy_issues=$((tidy_issues + 1))
else
echo "✅ Clean: $file"
fi
fi
done < cpp_files.txt
# Cleanup
rm -f cpp_files_all.txt cpp_files.txt
echo ""
echo "📊 Clang-tidy Summary:"
if [ $tidy_issues -gt 0 ]; then
echo "⚠️ Found potential issues in $tidy_issues files"
echo "Note: Some warnings may be false positives"
# Don't fail CI for now, just report
exit 0
else
echo "✅ No issues found in analyzed files!"
fi
- name: 🔧 Install cppcheck
if: env.SKIP_CPPCHECK != 'true'
run: |
sudo apt-get update
sudo apt-get install -y cppcheck
cppcheck --version
- name: ⏭️ Cppcheck analysis disabled
if: env.SKIP_CPPCHECK == 'true'
run: |
echo "⚠️ Cppcheck analysis is currently disabled"
echo "Set SKIP_CPPCHECK=false in workflow env to enable"
- name: 🔍 Run cppcheck analysis
if: env.SKIP_CPPCHECK != 'true'
shell: bash
run: |
echo "🔍 Running cppcheck analysis..."
# Run cppcheck on source directories
echo "📊 Analyzing C++ code for bugs and security issues..."
cppcheck_output="cppcheck_results.txt"
# Run cppcheck with comprehensive checks
cppcheck \
--enable=warning,style,performance,portability,information \
--std=c++17 \
--inline-suppr \
--quiet \
--template='{file}:{line}:{column}: {severity}: {message} [{id}]' \
--suppress=missingIncludeSystem \
--suppress=unmatchedSuppression \
--suppress=unusedFunction \
--suppress=noExplicitConstructor \
--error-exitcode=0 \
src/ \
2>&1 | tee "$cppcheck_output" || true
# Count different types of issues
total_issues=$(wc -l < "$cppcheck_output" || echo "0")
error_issues=$(grep -c ": error:" "$cppcheck_output" 2>/dev/null || echo "0")
warning_issues=$(grep -c ": warning:" "$cppcheck_output" 2>/dev/null || echo "0")
style_issues=$(grep -c ": style:" "$cppcheck_output" 2>/dev/null || echo "0")
performance_issues=$(grep -c ": performance:" "$cppcheck_output" 2>/dev/null || echo "0")
echo ""
echo "📊 Cppcheck Summary:"
echo " Total issues: $total_issues"
echo " Errors: $error_issues"
echo " Warnings: $warning_issues"
echo " Style: $style_issues"
echo " Performance: $performance_issues"
if [ "$total_issues" -gt 0 ]; then
echo ""
echo "🔍 Found issues (first 20):"
head -20 "$cppcheck_output"
if [ "$error_issues" -gt 0 ]; then
echo ""
echo "❌ Found $error_issues critical errors"
echo "Note: These should be reviewed and fixed"
else
echo ""
echo "⚠️ Found $total_issues potential issues"
echo "Note: Many may be false positives - review manually"
fi
# Don't fail CI for now, just report
exit 0
else
echo "✅ No issues found!"
echo "🎉 Cppcheck analysis passed!"
fi
# Cleanup
rm -f "$cppcheck_output"
- name: 🔧 Install include-what-you-use
if: env.SKIP_IWYU != 'true'
run: |
sudo apt-get update
sudo apt-get install -y iwyu
include-what-you-use --version || echo "IWYU installed successfully"
- name: ⏭️ IWYU analysis disabled
if: env.SKIP_IWYU == 'true'
run: |
echo "⚠️ Include-what-you-use analysis is currently disabled"
echo "Set SKIP_IWYU=false in workflow env to enable"
- name: 🔍 Run include-what-you-use analysis
if: env.SKIP_IWYU != 'true'
shell: bash
run: |
echo "🔍 Running include-what-you-use analysis..."
# Find C++ source files (focus on .cpp files for IWYU)
find . -name "*.cpp" \
-not -path "./build/*" \
-not -path "./cmake-build-*" \
-not -path "./.conan/*" \
-not -path "./third_party/*" \
-not -path "./ci_utils/*" > cpp_source_files.txt
# Take first 15 files to avoid overwhelming CI
head -15 cpp_source_files.txt > cpp_iwyu_files.txt
total_files=$(wc -l < cpp_source_files.txt)
check_files=$(wc -l < cpp_iwyu_files.txt)
echo "Found $total_files C++ source files total, analyzing first $check_files files"
if [ "$check_files" -eq 0 ]; then
echo "⚠️ No C++ source files found to analyze"
rm -f cpp_source_files.txt cpp_iwyu_files.txt
exit 0
fi
echo "📊 Analyzing include dependencies..."
iwyu_output="iwyu_results.txt"
iwyu_issues=0
processed_files=0
# Run IWYU on each file
while IFS= read -r file; do
if [ -f "$file" ]; then
echo "🔍 Analyzing includes in: $file"
processed_files=$((processed_files + 1))
# Run IWYU with basic flags
if ! include-what-you-use \
-std=c++17 \
-I./src \
-I./include \
"$file" \
2>> "$iwyu_output" >/dev/null; then
# IWYU always returns non-zero, so we check output instead
if grep -q "should add\|should remove\|full include-list" "$iwyu_output" 2>/dev/null; then
echo "💡 Suggestions found for: $file"
iwyu_issues=$((iwyu_issues + 1))
else
echo "✅ No changes needed: $file"
fi
fi
fi
done < cpp_iwyu_files.txt
echo ""
echo "📊 IWYU Analysis Summary:"
echo " Files analyzed: $processed_files"
echo " Files with suggestions: $iwyu_issues"
if [ "$iwyu_issues" -gt 0 ] && [ -f "$iwyu_output" ] && [ -s "$iwyu_output" ]; then
echo ""
echo "💡 Include optimization suggestions (first 30 lines):"
head -30 "$iwyu_output"
echo ""
echo "🔧 IWYU found $iwyu_issues files that could optimize their includes"
echo "Note: These are suggestions to reduce compile time and dependencies"
echo ""
echo "📄 Full report available in CI artifacts or run locally:"
echo " ./scripts/check-iwyu.sh"
else
echo ""
echo "✅ No include optimizations suggested!"
echo "🎉 Include dependencies are well-organized!"
fi
# Cleanup
rm -f cpp_source_files.txt cpp_iwyu_files.txt "$iwyu_output"
# Don't fail CI - IWYU suggestions are optional optimizations
exit 0