docs: announce v1.x on master and v0.x maintenance branch (#361) #1233
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | |