Skip to content

🎯 CI Sonar Scan #494

🎯 CI Sonar Scan

🎯 CI Sonar Scan #494

Workflow file for this run

# 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 }}