ci.yml 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. # .github/workflows/ci.yml
  2. # Main CI workflow - fast feedback for PRs and commits
  3. ---
  4. name: CI
  5. on:
  6. pull_request:
  7. branches: ["master"]
  8. push:
  9. branches: ["master"]
  10. permissions:
  11. contents: write
  12. issues: write
  13. pull-requests: write
  14. env:
  15. BUILD_TYPE: Release
  16. jobs:
  17. # Quick linting with standard checks
  18. lint:
  19. name: Lint (Standard)
  20. runs-on: ubuntu-latest
  21. steps:
  22. - name: Checkout Code
  23. uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
  24. with:
  25. fetch-depth: 0
  26. - name: MegaLinter
  27. uses: oxsecurity/megalinter/flavors/c_cpp@55a59b24a441e0e1943080d4a512d827710d4a9d
  28. id: ml
  29. env:
  30. VALIDATE_ALL_CODEBASE: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
  31. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  32. DISABLE_LINTERS: SPELL_CSPELL
  33. DISABLE_ERRORS: false
  34. # Fast standard checks - suppress normalCheckLevelMaxBranches info message
  35. C_CPPCHECK_ARGUMENTS: >-
  36. --inline-suppr
  37. --suppress=normalCheckLevelMaxBranches
  38. --suppress=missingIncludeSystem
  39. --suppress=missingInclude
  40. # Enable auto-fixes
  41. APPLY_FIXES: all
  42. APPLY_FIXES_EVENT: pull_request
  43. APPLY_FIXES_MODE: commit
  44. - name: Archive MegaLinter Reports
  45. if: always()
  46. uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
  47. with:
  48. name: megalinter-reports
  49. path: |
  50. megalinter-reports
  51. mega-linter.log
  52. - name: Prepare Commit
  53. if: >-
  54. steps.ml.outputs.has_updated_sources == 1 &&
  55. github.event_name == 'pull_request' &&
  56. github.event.pull_request.head.repo.full_name == github.repository &&
  57. !contains(github.event.head_commit.message, 'skip fix')
  58. run: sudo chown -Rc $UID .git/
  59. - name: Commit and Push Linter Fixes
  60. uses: stefanzweifel/git-auto-commit-action@28e16e81777b558cc906c8750092100bbb34c5e3
  61. if: >-
  62. steps.ml.outputs.has_updated_sources == 1 &&
  63. github.event_name == 'pull_request' &&
  64. github.event.pull_request.head.repo.full_name == github.repository &&
  65. !contains(github.event.head_commit.message, 'skip fix')
  66. with:
  67. branch: ${{ github.event.pull_request.head.ref }}
  68. commit_message: "[MegaLinter] Apply linter fixes"
  69. commit_user_name: megalinter-bot
  70. commit_user_email: 129584137+megalinter-bot@users.noreply.github.com
  71. # Build and test
  72. build-test:
  73. name: Build & Test
  74. runs-on: ubuntu-latest
  75. needs: lint
  76. if: success() || failure()
  77. steps:
  78. - name: Checkout Code
  79. uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
  80. with:
  81. fetch-depth: 0
  82. - name: Install Dependencies
  83. run: |
  84. sudo apt-get update
  85. sudo apt-get install -y \
  86. libcap-dev \
  87. lcov \
  88. cpputest
  89. - name: Set up Python
  90. uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548
  91. with:
  92. python-version: "3.11"
  93. - name: Install gcovr
  94. run: pip install gcovr
  95. - name: Configure CMake
  96. run: |
  97. cmake -S ${{ github.workspace }}/source \
  98. -B ${{ github.workspace }}/build \
  99. -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
  100. -DOpENer_PLATFORM:STRING="POSIX" \
  101. -DBUILD_SHARED_LIBS:BOOL=OFF \
  102. -DOpENer_TRACES:BOOL=OFF \
  103. -DOpENer_TESTS:BOOL=ON \
  104. -DCPPUTEST_HOME:PATH=/usr
  105. - name: Build
  106. run: cmake --build "${{ github.workspace }}/build" --config "${{ env.BUILD_TYPE }}" -j "$(nproc)"
  107. - name: Test
  108. working-directory: ${{ github.workspace }}/build
  109. run: ctest -C "${{ env.BUILD_TYPE }}" --output-on-failure --parallel "$(nproc)"
  110. - name: Generate Coverage Reports
  111. run: |
  112. gcovr --html-details --output coverage-report.html
  113. gcovr --cobertura --output coverage.xml
  114. gcovr --print-summary | tee coverage-summary.txt
  115. - name: Upload Coverage Reports
  116. uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
  117. with:
  118. name: coverage-report
  119. path: |
  120. coverage-report*.html
  121. coverage.xml
  122. coverage-summary.txt
  123. - name: Comment Coverage on PR
  124. if: github.event_name == 'pull_request'
  125. uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd
  126. continue-on-error: true
  127. with:
  128. script: |
  129. const fs = require('fs');
  130. const summary = fs.readFileSync('coverage-summary.txt', 'utf8');
  131. // Extract coverage percentage for badge
  132. const match = summary.match(/lines:\s+(\d+\.\d+)%/);
  133. const percentage = match ? match[1] : 'N/A';
  134. const artifactUrl = `https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}`;
  135. const comment = `## 📊 Coverage Report
  136. **Line Coverage: ${percentage}%**
  137. \`\`\`
  138. ${summary}
  139. \`\`\`
  140. 📥 Download the [detailed HTML report](${artifactUrl}) from artifacts.
  141. ℹ️ This PR was tested with **standard** static analysis. Exhaustive analysis will run on release branches.`;
  142. github.rest.issues.createComment({
  143. issue_number: context.issue.number,
  144. owner: context.repo.owner,
  145. repo: context.repo.repo,
  146. body: comment
  147. });
  148. - name: Upload Build Artifacts
  149. if: success()
  150. uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
  151. with:
  152. name: build-artifacts
  153. path: ${{ github.workspace }}/build
  154. retention-days: 7