🎯 CI Sonar Scan #494
This file contains 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
# Static code analysis workflow for Sonar Cloud, results are published to projects: | |
# - Windows: https://sonarcloud.io/project/overview?id=methane-powered-kit-windows | |
# - Linux: https://sonarcloud.io/project/overview?id=methane-powered-kit-linux | |
# - MacOS: https://sonarcloud.io/project/overview?id=methane-powered-kit-macos | |
name: '🎯 CI Sonar Scan' | |
on: | |
push: | |
branches: [ master, develop ] | |
paths: | |
- '.github/**/*sonar*.yml' | |
- 'sonar-project.properties' | |
- 'Apps/**' | |
- 'Modules/**' | |
- 'Tests/**' | |
- 'Externals/**' | |
- 'CMake/**' | |
- 'CMakeLists.txt' | |
- 'CMakePresets.json' | |
pull_request: | |
branches: [ master ] | |
types: [opened, synchronize, reopened] | |
paths: | |
- '.github/**/*sonar*.yml' | |
- 'sonar-project.properties' | |
- 'Apps/**' | |
- 'Modules/**' | |
- 'Tests/**' | |
- 'Externals/**' | |
- 'CMake/**' | |
- 'CMakeLists.txt' | |
- 'CMakePresets.json' | |
schedule: | |
- cron: '20 23 * * 3' # Scheduled workflow will not run in GitHub forks by default | |
env: | |
product_ver_major: 0 | |
product_ver_minor: 7 | |
product_ver_patch: 3 | |
product_ver_build: ${{ github.run_number }} | |
sonar_server_url: "https://sonarcloud.io" | |
sonar_organization: methane-powered | |
TRACY_NO_INVARIANT_CHECK: 1 | |
jobs: | |
sonar_scan: | |
name: ${{ matrix.name }} | |
if: ${{ github.repository == 'MethanePowered/MethaneKit' }} | |
strategy: | |
fail-fast: false | |
matrix: | |
include: | |
- os: windows-latest | |
os_name: windows | |
name: "Win64_DX_SonarScan" | |
named_logo: Windows | |
config_preset: "Ninja-Win-DX-Scan" | |
build_preset: "Ninja-Win-DX-Scan" | |
sonar_project_key: "methane-powered-kit-windows" | |
tests_coverage_reports: "Build/Output/Ninja-Win-DX-Scan/Install/Tests/Coverage/*.xml" | |
- os: ubuntu-latest | |
os_name: linux | |
name: "Ubuntu_VK_SonarScan" | |
named_logo: Linux | |
config_preset: "Ninja-Lin-VK-Scan" | |
build_preset: "Ninja-Lin-VK-Scan" | |
sonar_project_key: "methane-powered-kit-linux" | |
tests_coverage_reports: "Build/Output/Ninja-Lin-VK-Scan/Build/MethaneTestCoverage.info" | |
- os: macos-latest | |
os_name: macosx | |
name: "MacOS_MTL_SonarScan" | |
named_logo: Apple | |
config_preset: "Ninja-Mac-MTL-Scan" | |
build_preset: "Ninja-Mac-MTL-Scan" | |
sonar_project_key: "methane-powered-kit-macos" | |
tests_coverage_reports: "Build/Output/Ninja-Mac-MTL-Scan/Install/Tests/Coverage/*.lcov" | |
runs-on: ${{ matrix.os }} | |
env: | |
BUILD_DIR: Build/Output/${{ matrix.config_preset }}/Build | |
INSTALL_DIR: Build/Output/${{ matrix.config_preset }}/Install | |
BUILD_LOG_FILE: Build/Output/${{ matrix.config_preset }}/Install/Build.log | |
COVERAGE_LOG_FILE: Build/Output/${{ matrix.config_preset }}/Install/Coverage.log | |
SCAN_LOG_FILE: Build/Output/${{ matrix.config_preset }}/Install/SonarScan.log | |
COMPILE_COMMANDS_FILE: Build/Output/${{ matrix.config_preset }}/Build/compile_commands.json | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@v3 | |
with: | |
fetch-depth: 0 | |
- name: Install Linux prerequisites | |
if: ${{ matrix.os_name == 'linux' }} | |
run: | | |
sudo apt update | |
sudo apt install xcb libx11-dev libx11-xcb-dev libxcb-sync-dev libxcb-randr0-dev lcov | |
- name: Install Testspace | |
uses: testspace-com/setup-testspace@v1 | |
with: | |
domain: ${{ github.repository_owner }} | |
- name: Install .NET Core # Required to use ReportGenerator | |
uses: actions/setup-dotnet@v3 | |
with: | |
dotnet-version: 6.0.400 | |
- name: Install Sonar-Scanner | |
uses: sonarsource/sonarcloud-github-c-cpp@v2 | |
- name: Install Ninja | |
uses: MethanePowered/gha-setup-ninja@master | |
with: | |
version: 1.11.1 | |
- name: Initialize Externals Cache | |
uses: actions/cache@v3 | |
with: | |
path: Build/Output/ExternalsCache | |
key: ExternalsCache-${{ matrix.config_preset }}-${{ hashFiles('Externals/*.cmake') }} | |
- name: Setup Developer Command Prompt for MSVC (VS2022 x64) to build with Ninja | |
if: ${{ matrix.os_name == 'windows' }} | |
uses: ilammy/msvc-dev-cmd@v1 | |
with: | |
arch: x64 | |
- name: CMake Configure Preset ${{ matrix.config_preset }} | |
shell: bash | |
run: | | |
set -o pipefail | |
mkdir -p "$INSTALL_DIR" | |
# set METHANE_VERSION_BUILD=0 to benefit from SonarCloud analysis cache, build version invalidates cache at each run | |
cmake --preset ${{ matrix.config_preset }} -DMETHANE_VERSION_MAJOR=${{ env.product_ver_major }} -DMETHANE_VERSION_MINOR=${{ env.product_ver_minor }} -DMETHANE_VERSION_PATCH=${{ env.product_ver_patch }} -DMETHANE_VERSION_BUILD=0 2>&1 | tee $BUILD_LOG_FILE | |
ls -la "$BUILD_DIR" 2>&1 | tee -a $BUILD_LOG_FILE | |
if [ -f $COMPILE_COMMANDS_FILE ]; then | |
cp "$COMPILE_COMMANDS_FILE" "$INSTALL_DIR" | |
else | |
echo "Compile commands file was not found!" | |
fi | |
- name: CMake Build Preset ${{ matrix.build_preset }} | |
shell: bash | |
run: | | |
set -o pipefail | |
cmake --build --preset ${{ matrix.build_preset }} --target install 2>&1 | tee -a $BUILD_LOG_FILE | |
- name: Download OpenCppCoverage | |
if: ${{ matrix.os_name == 'windows' }} | |
shell: powershell | |
working-directory: 'Build/Output/${{ matrix.config_preset }}/Install/Tests' | |
run: | | |
Invoke-WebRequest -Uri 'https://github.com/MethanePowered/OpenCppCoverage/releases/download/release-0.9.9.0/OpenCppCoverage.zip' -OutFile 'OpenCppCoverage.zip' | |
Expand-Archive -Path 'OpenCppCoverage.zip' -DestinationPath 'OpenCppCoverage' | |
if (-not(Test-Path -Path 'OpenCppCoverage/OpenCppCoverage.exe' -PathType Leaf)) { | |
Get-ChildItem 'OpenCppCoverage' | |
throw 'OpenCppCoverage/OpenCppCoverage.exe executable was not found in unpacked content!' | |
} | |
- name: Run all unit-tests with OpenCppCoverage code coverage on Windows | |
if: ${{ matrix.os_name == 'windows' }} | |
shell: cmd | |
working-directory: 'Build\Output\${{ matrix.config_preset }}\Install\Tests' | |
run: | | |
chcp 65001 #set code page to utf-8 | |
setlocal enabledelayedexpansion | |
set open_cpp_coverage_exe=OpenCppCoverage\OpenCppCoverage.exe | |
set test_results= | |
if not exist "%open_cpp_coverage_exe%" ( | |
echo File path "%open_cpp_coverage_exe%" does not exist! | |
exit 101 | |
) | |
echo Running unit-tests in directory "%cd%" | |
mkdir Results | |
mkdir Coverage | |
set /A result_error_level=0 | |
for /r "." %%a in (*Test.exe) do ( | |
echo %open_cpp_coverage_exe% --sources "${{ github.workspace }}\Modules" --export_type=cobertura:Coverage\%%~na.xml -- "%%~fa" -r sonarqube -o "Results\%%~na.xml" | |
%open_cpp_coverage_exe% --sources "${{ github.workspace }}\Modules" --export_type=cobertura:Coverage\%%~na.xml -- "%%~fa" -r sonarqube -o "Results\%%~na.xml" | |
echo - %%~na - completed with !errorlevel! exit status | |
if not !errorlevel!==0 ( | |
set /A result_error_level=!errorlevel! | |
) | |
if .!test_results!==. ( | |
set test_results=Build/Output/${{ matrix.config_preset }}/Install/Tests/Results/%%~na.xml | |
) else ( | |
set test_results=!test_results!,Build/Output/${{ matrix.config_preset }}/Install/Tests/Results/%%~na.xml | |
) | |
) | |
echo Test Result Files: %test_results% | |
echo test_results=%test_results%>> %GITHUB_ENV% | |
exit !result_error_level! | |
- name: Run all unit-tests with GCov code coverage on Linux | |
if: ${{ matrix.os_name == 'linux' }} | |
working-directory: 'Build/Output/${{ matrix.config_preset }}/Install/Tests' | |
run: | | |
set +e | |
result_ext='.xml' | |
test_results='' | |
result_error_level=0 | |
echo Running unit-tests in directory $PWD | |
mkdir Results | |
for test_exe in *Test | |
do | |
./$test_exe -r sonarqube -o "Results/$test_exe$result_ext" | |
last_error_level=$? | |
echo - $test_exe - completed with $last_error_level exit status | |
if [ $last_error_level != 0 ]; then | |
result_error_level=$last_error_level | |
fi | |
if [ -f "$PWD/Results/$test_exe$result_ext" ]; then | |
test_results+="$PWD/Results/$test_exe$result_ext," | |
fi | |
done | |
echo "Test Result Files: $test_results" | |
echo "test_results=$test_results" >> $GITHUB_ENV | |
exit $result_error_level | |
- name: Collect tests code coverage using ctest and gcov/lcov on Linux | |
if: ${{ matrix.os_name == 'linux' && (success() || failure()) }} | |
run: | | |
set -o pipefail | |
cmake --build --preset ${{ matrix.build_preset }} --target MethaneTestCoverage 2>&1 | tee $COVERAGE_LOG_FILE | |
- name: Run all unit-tests with LCov code coverage on MacOS | |
if: ${{ matrix.os_name == 'macosx' }} | |
working-directory: 'Build/Output/${{ matrix.config_preset }}/Install/Tests' | |
run: | | |
set +e | |
result_error_level=0 | |
result_ext='.xml' | |
prof_data_ext='.profdata' | |
prof_raw_ext='.profraw' | |
lcov_ext='.lcov' | |
test_results='' | |
echo Running unit-tests and Converting LLVM code coverage data to lcov text format in directory $PWD | |
mkdir Results | |
mkdir Coverage | |
for test_exe in *Test | |
do | |
./$test_exe -r sonarqube -o "Results/$test_exe$result_ext" | |
last_error_level=$? | |
echo - $test_exe - completed with $last_error_level exit status | |
if [ $last_error_level != 0 ]; then | |
result_error_level=$last_error_level | |
fi | |
if [ -f "$PWD/Results/$test_exe$result_ext" ]; then | |
test_results+="$PWD/Results/$test_exe$result_ext," | |
fi | |
if [ ! -f default.profraw ]; then | |
continue | |
fi | |
mv default.profraw "$test_exe$prof_raw_ext" | |
xcrun llvm-profdata merge -o "$test_exe$prof_data_ext" "$test_exe$prof_raw_ext" | |
xcrun llvm-cov export -format lcov -instr-profile="$test_exe$prof_data_ext" -arch=x86_64 ./$test_exe > "./Coverage/$test_exe$lcov_ext" | |
echo - Converted code coverage from "$test_exe$prof_raw_ext" to lcov text format "./Coverage/$test_exe$lcov_ext", $? exit status | |
done | |
echo "Test Result Files: $test_results" | |
echo "test_results=$test_results" >> $GITHUB_ENV | |
echo List of generated coverage files in directory $PWD/Coverage | |
ls -la ./Coverage | |
exit $result_error_level | |
- name: Generate Code Coverage Reports | |
if: ${{ success() || failure() }} | |
uses: danielpalme/[email protected] | |
with: | |
reports: ${{ matrix.tests_coverage_reports }} | |
targetdir: 'Build/Output/${{ matrix.config_preset }}/Install/Tests/Coverage/Report' | |
reporttypes: 'Cobertura;SonarQube' | |
title: 'Methane Tests Code Coverage for ${{ matrix.build_preset }}' | |
tag: '${{ env.product_ver_major }}.${{ env.product_ver_minor }}.${{ env.product_ver_patch }}.${{ env.product_ver_build }}' | |
- name: Upload Code Coverage Cobertura Report | |
if: ${{ success() || failure() }} | |
uses: actions/upload-artifact@v3 | |
with: | |
name: MethaneKit_${{ matrix.name }}_CoverageResults | |
path: Build/Output/${{ matrix.config_preset }}/Install/Tests/Coverage/Report/Cobertura.xml | |
- name: Upload Build Log and Code Coverage to Testspace server | |
if: ${{ success() || failure() }} | |
run: testspace "[ ${{ matrix.name }} ]Build/Output/${{ matrix.config_preset }}/Install/Tests/Coverage/Report/Cobertura.xml" "[ ${{ matrix.name }} ]${{ env.BUILD_LOG_FILE }}" | |
- name: Upload Code Coverage to CodeCov server | |
if: ${{ success() || failure() }} | |
uses: codecov/codecov-action@v3 | |
with: | |
files: Build/Output/${{ matrix.config_preset }}/Install/Tests/Coverage/Report/Cobertura.xml | |
flags: unittests,${{ matrix.os_name }} | |
name: ${{ matrix.name }} | |
- name: Run Sonar Scanner | |
if: ${{ success() || failure() }} | |
shell: bash | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
run: | | |
if [ "${{ matrix.os_name }}" == "windows" ]; then | |
SONAR_SCANNER_EXE=sonar-scanner.bat | |
else | |
SONAR_SCANNER_EXE=sonar-scanner | |
fi | |
# SONAR_SCANNER_EXE="$SONAR_SCANNER_EXE -X" # Uncomment to enable debug output | |
TESTS_DIR=Build/Output/${{ matrix.config_preset }}/Install/Tests | |
SONAR_SCAN_CMD="$SONAR_SCANNER_EXE --define sonar.host.url=${{ env.sonar_server_url }}" | |
SONAR_SCAN_CMD="$SONAR_SCAN_CMD --define sonar.organization=${{ env.sonar_organization }}" | |
SONAR_SCAN_CMD="$SONAR_SCAN_CMD --define sonar.projectKey=${{ matrix.sonar_project_key }}" | |
SONAR_SCAN_CMD="$SONAR_SCAN_CMD --define sonar.projectVersion=${{ env.product_ver_major }}.${{ env.product_ver_minor }}.${{ env.product_ver_patch }}.${{ env.product_ver_build }}" | |
SONAR_SCAN_CMD="$SONAR_SCAN_CMD --define sonar.cfamily.compile-commands=Build/Output/${{ matrix.config_preset }}/Build/compile_commands.json" | |
SONAR_SCAN_CMD="$SONAR_SCAN_CMD --define sonar.testExecutionReportPaths=${{ env.test_results }}" | |
SONAR_SCAN_CMD="$SONAR_SCAN_CMD --define sonar.coverageReportPaths=$TESTS_DIR/Coverage/Report/SonarQube.xml" | |
SONAR_SCAN_CMD="$SONAR_SCAN_CMD --define sonar.scm.revision=${{ github.sha }}" | |
if [ "${{ github.event_name }}" == "pull_request" ]; then | |
SONAR_SCAN_CMD="$SONAR_SCAN_CMD --define sonar.pullrequest.provider=GitHub" | |
SONAR_SCAN_CMD="$SONAR_SCAN_CMD --define sonar.pullrequest.github.repository=MethanePowered/MethaneKit" | |
SONAR_SCAN_CMD="$SONAR_SCAN_CMD --define sonar.pullrequest.key=${{ github.event.pull_request.number }}" | |
SONAR_SCAN_CMD="$SONAR_SCAN_CMD --define sonar.pullrequest.branch=${{ github.event.pull_request.head.ref }}" | |
SONAR_SCAN_CMD="$SONAR_SCAN_CMD --define sonar.pullrequest.base=${{ github.event.pull_request.base.ref }}" | |
fi | |
set -o pipefail | |
echo "$SONAR_SCAN_CMD" | tee $SCAN_LOG_FILE | |
eval "$SONAR_SCAN_CMD" 2>&1 | tee -a $SCAN_LOG_FILE | |
cp sonar-project.properties $INSTALL_DIR | |
prop_files=(`find .sonar -name "sonar-scanner.properties"`) | |
for prop_file in "${prop_files[@]}"; do | |
cp $prop_file $INSTALL_DIR | |
done | |
- name: Archive Scan Artifacts | |
if: ${{ success() || failure() }} | |
shell: bash | |
working-directory: Build/Output/${{ matrix.config_preset }}/Install | |
run: 7z a -t7z -mx=9 MethaneKit_${{ matrix.name }}.7z * | |
- name: Upload Archived Scan Artifacts | |
if: ${{ success() || failure() }} | |
uses: actions/upload-artifact@v3 | |
with: | |
name: MethaneKit_${{ matrix.name }}_${{ env.product_ver_major }}.${{ env.product_ver_minor }}.${{ env.product_ver_patch }}.${{ env.product_ver_build }} | |
path: Build/Output/${{ matrix.config_preset }}/Install/MethaneKit_${{ matrix.name }}.7z | |
- name: Update Badge Parameters | |
if: ${{ github.event_name == 'push' && always() }} | |
shell: bash | |
run: | | |
case "${{ job.status }}" in | |
"success") | |
echo "badge_message=passed" >> $GITHUB_ENV | |
echo "badge_color=#56a93c" >> $GITHUB_ENV | |
;; | |
"failure") | |
echo "badge_message=failed" >> $GITHUB_ENV | |
echo "badge_color=#cd6e57" >> $GITHUB_ENV | |
;; | |
"cancelled") | |
echo "badge_message=cancelled" >> $GITHUB_ENV | |
echo "badge_color=#9b9b9c" >> $GITHUB_ENV | |
;; | |
*) | |
echo "badge_message=undefined" >> $GITHUB_ENV | |
echo "badge_color=purple" >> $GITHUB_ENV | |
;; | |
esac | |
- name: Update Badge JSON | |
if: ${{ github.event_name == 'push' && always() }} | |
uses: schneegans/[email protected] # https://github.com/marketplace/actions/dynamic-badges | |
with: | |
auth: ${{ secrets.GIST_TOKEN }} | |
gistID: 96d788046ccd52b45b3354a99f8569c3 | |
filename: MethaneKit_${{ matrix.name }}_${{ github.ref_name }}.json | |
namedLogo: ${{ matrix.named_logo }} # https://simpleicons.org | |
label: ${{ matrix.name }} | |
labelColor: #f5f5f5 | |
logoColor: #f5f5f5 | |
message: ${{ env.badge_message }} | |
color: ${{ env.badge_color }} |