.github/workflows/reusable-native.yml
name: Reusable Native workflow
on:
workflow_call:
inputs:
name:
type: string
required: true
host_os:
type: string
required: true
type:
type: string
required: true
compiler:
type: string
required: true
qt_host:
type: string
required: false
qt_version:
type: string
required: false
qt_arch:
type: string
required: false
defaults:
run:
shell: sh
working-directory: .
# Default environment variables.
env:
GITHUB_STEP_TIMEOUT_SMALL: 4
GITHUB_STEP_TIMEOUT_MEDIUM: 10
GITHUB_STEP_TIMEOUT_LONG: 20
jobs:
Build:
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
name: ${{ inputs.name }} ${{ inputs.host_os }} (${{ inputs.type }})
runs-on: ${{ inputs.host_os }}
timeout-minutes: 360
steps:
- name: Checkout
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_MEDIUM) }}
if: success()
uses: actions/checkout@v4
- name: Check MacOS Xcode versions
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success() && startsWith(inputs.host_os, 'macos')
working-directory: .
run: |
ls -lahp /System/Volumes/Data/Applications;
- name: Check Windows Visual Studio versions
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success() && startsWith(inputs.host_os, 'windows-2022')
working-directory: .
run: |
ls -lahp "C:/Program Files/Microsoft Visual Studio/";
visualStudioVersion=$(ls -la "C:/Program Files/Microsoft Visual Studio/" | grep ".*[[:digit:]]$" | awk '{print $(NF)}' | tail -1);
echo "Detected Visual Studio version: ${visualStudioVersion}";
msvcVersion=$(ls -la "C:/Program Files/Microsoft Visual Studio/${visualStudioVersion}/Enterprise/VC/Tools/MSVC/" | grep "[[:digit:]]\.[[:digit:]].*" | awk '{print $(NF)}' | tail -1);
echo "Detected Visual Studio C++ Compiler version: ${msvcVersion}";
ls -lahp "C:/Program Files/Microsoft Visual Studio/${visualStudioVersion}/Enterprise/MSBuild/";
ls -lahp "C:/Program Files/Microsoft Visual Studio/${visualStudioVersion}/Enterprise/MSBuild/Current/Bin/";
ls -lahp "C:/Program Files/Microsoft Visual Studio/${visualStudioVersion}/Enterprise/MSBuild/Current/Bin/amd64/";
ls -lahp "C:/Program Files/Microsoft Visual Studio/${visualStudioVersion}/Enterprise/MSBuild/Current/Bin/amd64/MSBuild.exe";
ls -lahp "C:/Program Files/Microsoft Visual Studio/${visualStudioVersion}/Enterprise/VC/Tools/MSVC/";
ls -lahp "C:/Program Files/Microsoft Visual Studio/${visualStudioVersion}/Enterprise/VC/Tools/MSVC/${msvcVersion}/bin/Hostx64/x64/cl.exe";
- name: Install MacPorts (MacOS 11)
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_MEDIUM) }}
if: success() && startsWith(inputs.host_os, 'macos-11')
uses: melusina-org/setup-macports@v1
with:
# Check available parameters in: https://github.com/melusina-org/setup-macports/blob/main/action.yaml
parameters: '.github/macports.yml'
- name: Delete Qt path
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success() && (startsWith(inputs.host_os, 'windows') || startsWith(inputs.host_os, 'macos-12'))
working-directory: .
run: |
# This step is to avoid the following error during the step "Install Qt (Windows & MacOS)":
# Cannot create output directory : Cannot create a file when that file already exists. : D:\a\MobileRT\MobileRT\Qt\6.9.0\msvc2022_64
rm -rf Qt;
- name: Install Qt (Windows & MacOS)
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_MEDIUM) }}
if: success() && (startsWith(inputs.host_os, 'windows') || startsWith(inputs.host_os, 'macos-12'))
uses: jurplel/install-qt-action@v4
# Download Qt from: https://download.qt.io/online/qtsdkrepository/
with:
# Check available parameters in: https://github.com/jurplel/install-qt-action/blob/master/action.yml
version: '${{ inputs.qt_version }}' # Also update: app/CMakeLists.txt
host: '${{ inputs.qt_host }}'
target: 'desktop'
arch: '${{ inputs.qt_arch }}'
dir: '${{ github.workspace }}'
install-deps: 'false'
modules: ''
cache: 'true'
cache-key-prefix: '${{ inputs.qt_host }}-${{ inputs.qt_arch }}'
setup-python: 'false'
set-env: 'true'
tools-only: 'false'
aqtversion: '==3.1.*'
py7zrversion: '==0.20.*'
extra: '--external 7z'
- name: Install dependencies
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_LONG) }}
if: success()
working-directory: .
run: |
sh scripts/install_dependencies.sh;
- name: Check Qt path installation MacOS
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success() && startsWith(inputs.host_os, 'macos')
working-directory: .
run: |
set +e;
test -d /opt/homebrew/Cellar/qt@5;
qtPathFromHomebrewForMacOS14=$?;
test -d /usr/local/Cellar/qt@5;
qtPathFromHomebrewForMacOS13=$?;
test -d /opt/local/libexec/qt5;
qtPathFromMacPortsForMacOS12=$?;
set -e;
if [ "${qtPathFromHomebrewForMacOS14}" = '0' ]; then
echo 'Adding Qt v5 lib path to compiler in MacOS-14';
qtVersion=$(ls -t '/opt/homebrew/Cellar/qt@5/' | head -1);
echo "Detected Qt version: ${qtVersion}";
echo "Qt5_DIR=/opt/homebrew/Cellar/qt@5/${qtVersion}/lib/cmake/Qt5" >> "${GITHUB_ENV}";
echo "CPPFLAGS=${CPPFLAGS} -I/opt/homebrew/opt/qt@5/include" >> "${GITHUB_ENV}";
echo "LDFLAGS=${LDFLAGS} -L/opt/homebrew/opt/qt@5/lib" >> "${GITHUB_ENV}";
elif [ "${qtPathFromHomebrewForMacOS13}" = '0' ]; then
echo 'Adding Qt v5 lib path to compiler in MacOS-13 & MacOS-12';
qtVersion=$(ls -t '/usr/local/Cellar/qt@5/' | head -1);
echo "Detected Qt version: ${qtVersion}";
echo "Qt5_DIR=/usr/local/Cellar/qt@5/${qtVersion}/lib/cmake/Qt5" >> "${GITHUB_ENV}";
echo "CPPFLAGS=${CPPFLAGS} -I/usr/local/opt/qt@5/include" >> "${GITHUB_ENV}";
echo "LDFLAGS=${LDFLAGS} -L/usr/local/opt/qt@5/lib" >> "${GITHUB_ENV}";
elif [ "${qtPathFromMacPortsForMacOS12}" = '0' ]; then
echo 'Adding Qt v5 lib path to compiler in MacOS-12';
echo "Qt5_DIR=/opt/local/lib/cmake/Qt5" >> "${GITHUB_ENV}";
echo "CPPFLAGS=${CPPFLAGS} -I/opt/local/libexec/qt5/include" >> "${GITHUB_ENV}";
echo "LDFLAGS=${LDFLAGS} -L/opt/local/libexec/qt5/lib" >> "${GITHUB_ENV}";
else
echo 'Expecting Qt was installed in MobileRT root path.';
env | grep -ie qt -ie flags;
du -h -d 1 Qt;
fi
- name: Install Intel C++ Compiler
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success() && startsWith(inputs.compiler, 'icpx')
working-directory: .
run: |
gpgKey='GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB';
wget https://apt.repos.intel.com/intel-gpg-keys/"${gpgKey}";
sudo apt-key add "${gpgKey}";
rm "${gpgKey}";
echo 'deb https://apt.repos.intel.com/oneapi all main' | sudo tee /etc/apt/sources.list.d/oneAPI.list;
sudo rm /etc/apt/sources.list.d/microsoft-prod.list || true;
sudo apt-get update;
sudo apt-get install intel-oneapi-compiler-dpcpp-cpp;
. /opt/intel/oneapi/setvars.sh;
env;
which icpx;
which icx;
echo 'Storing LD_LIBRARY_PATH & PATH in workflow environment variables.';
echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" >> "${GITHUB_ENV}";
echo "PATH=${PATH}" >> "${GITHUB_ENV}";
- name: Build ${{ inputs.type }}
timeout-minutes: 40
if: success()
working-directory: .
run: |
sh scripts/compile_native.sh -t ${{ inputs.type }} -c ${{ inputs.compiler }};
- name: Generate code coverage base
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success() && startsWith(inputs.host_os, 'ubuntu') && inputs.type == 'debug' && startsWith(inputs.compiler, 'g++')
working-directory: .
run: |
lcov -c -i -d . --no-external -o code_coverage_base.info;
- name: Set sanitizer configs for Ubuntu
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success() && startsWith(inputs.host_os, 'ubuntu')
working-directory: .
run: |
ls -lahp scripts/sanitizer_ignore.suppr;
export ASAN_OPTIONS='suppressions=scripts/sanitizer_ignore.suppr:verbosity=1:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:halt_on_error=0:detect_odr_violation=1:detect_leaks=1:detect_container_overflow=1';
export LSAN_OPTIONS='suppressions=scripts/sanitizer_ignore.suppr:verbosity=1:strict_string_checks=1';
echo "ASAN_OPTIONS=${ASAN_OPTIONS}" >> "${GITHUB_ENV}";
echo "LSAN_OPTIONS=${LSAN_OPTIONS}" >> "${GITHUB_ENV}";
- name: Set sanitizer configs for MacOS
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success() && startsWith(inputs.host_os, 'macos')
working-directory: .
run: |
ls -lahp scripts/sanitizer_ignore.suppr;
export ASAN_OPTIONS='suppressions=scripts/sanitizer_ignore.suppr:verbosity=1:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:halt_on_error=0:detect_odr_violation=1:detect_container_overflow=1';
export LSAN_OPTIONS='suppressions=scripts/sanitizer_ignore.suppr:verbosity=1:strict_string_checks=1';
echo "ASAN_OPTIONS=${ASAN_OPTIONS}" >> "${GITHUB_ENV}";
echo "LSAN_OPTIONS=${LSAN_OPTIONS}" >> "${GITHUB_ENV}";
- name: Run unit tests
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success()
working-directory: .
run: |
unitTestsExe=$(find build_${{ inputs.type }} -type f -name "UnitTests*" | head -1);
echo "Unit tests executable: ${unitTestsExe}";
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:$(find ~/.conan -iname 'libgtest.so' | grep -iv 'build' | xargs ls -t | head -1 | xargs dirname)" ${unitTestsExe} --gtest_filter=-*Engine*;
- name: Run system tests Ray Tracing engine (for code coverage)
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success()
working-directory: .
run: |
ls -la ./app/src/androidTest/resources/CornellBox/CornellBox-Water.obj;
ls -la ./app/src/androidTest/resources/CornellBox/CornellBox-Water.mtl;
ls -la ./app/src/androidTest/resources/CornellBox/CornellBox-Water.cam;
unitTestsExe=$(find build_${{ inputs.type }} -type f -name "UnitTests*" | head -1);
echo "Unit tests executable: ${unitTestsExe}";
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:$(find ~/.conan -iname 'libgtest.so' | grep -iv 'build' | xargs ls -t | head -1 | xargs dirname)" ${unitTestsExe} --gtest_filter=*Engine*;
- name: Create symbolic links for Qt in MacOS
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success() && startsWith(inputs.host_os, 'macos')
working-directory: .
run: |
otool -L ${PWD}/build_${{ inputs.type }}/bin/AppMobileRT*;
sudo ln -s ${Qt5_DIR}/lib/QtCore.framework /Library/Frameworks;
sudo ln -s ${Qt5_DIR}/lib/QtGui.framework /Library/Frameworks;
sudo ln -s ${Qt5_DIR}/lib/QtWidgets.framework /Library/Frameworks;
- name: Test MobileRT ${{ inputs.type }}
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success()
working-directory: .
run: |
ls -lahp scripts/sanitizer_ignore.suppr;
export ASAN_OPTIONS='suppressions=scripts/sanitizer_ignore.suppr:verbosity=1:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:halt_on_error=0:detect_odr_violation=1:detect_leaks=1:detect_container_overflow=1';
export LSAN_OPTIONS='suppressions=scripts/sanitizer_ignore.suppr:verbosity=1:strict_string_checks=1';
set +e;
if [ "${{ inputs.type }}" = 'release' ]; then
timeoutSeconds='15';
else
timeoutSeconds='100';
fi
sh scripts/profile.sh timeout "${{ inputs.type }}" 100 "${timeoutSeconds}";
returnValue="$?";
set -e;
# shellcheck disable=SC1091
. scripts/test/utils/utils.sh && assertEqual '124' "${returnValue}" "test profile script: ${{ inputs.type }}";
if [ "${returnValue}" != '124' ]; then
exit "${returnValue}"; # Exit with error if test failed.
fi
# TODO: Investigate how to use 'perf record' in github actions machines.
- name: Profile MobileRT ${{ inputs.type }}
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success() && inputs.type == 'release' && startsWith(inputs.host_os, 'ubuntu')
working-directory: .
run: |
sudo sysctl kernel.yama.ptrace_scope=0;
sudo sysctl kernel.yama.ptrace_scope;
sudo sysctl kernel.kptr_restrict=0;
sudo sysctl kernel.kptr_restrict;
sudo sysctl kernel.nmi_watchdog=0;
sudo sysctl kernel.nmi_watchdog;
sudo sysctl kernel.perf_event_paranoid=-1;
sudo sysctl kernel.perf_event_paranoid;
sudo sysctl vm.max_map_count=100000000;
sudo sysctl vm.max_map_count;
sudo sysctl kernel.perf_event_max_sample_rate=3250;
sudo sysctl kernel.perf_event_max_sample_rate;
sudo sysctl net.ipv4.tcp_timestamps=0;
sudo sysctl net.ipv4.tcp_timestamps;
sh scripts/profile.sh perf "${{ inputs.type }}" 500;
- name: Generate code coverage
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success() && startsWith(inputs.host_os, 'ubuntu') && inputs.type == 'debug' && startsWith(inputs.compiler, 'g++')
working-directory: .
run: |
# shellcheck disable=SC1091
. scripts/helper_functions.sh && generateCodeCoverage;
- name: Upload coverage to cache
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success() && startsWith(inputs.host_os, 'ubuntu') && inputs.type == 'debug' && startsWith(inputs.compiler, 'g++')
uses: actions/cache@v4
with:
# Check available parameters in: https://github.com/actions/cache/blob/main/action.yml
key: reports_${{ github.sha }}_${{ github.run_id }}_${{ github.run_number }}_${{ inputs.name }}_${{ inputs.host_os }}_${{ inputs.type }}_${{ inputs.compiler }}
restore-keys: reports_${{ github.sha }}_${{ github.run_id }}_${{ github.run_number }}_${{ inputs.name }}_${{ inputs.host_os }}_${{ inputs.type }}_${{ inputs.compiler }}
path: |
code_coverage_base.info
code_coverage.info
code_coverage_test.info
code_coverage_filtered.info
Sonar:
needs: [Build]
if: inputs.type == 'debug'
name: Code Coverage ${{ inputs.type }} (${{ inputs.host_os }})
runs-on: ${{ inputs.host_os }}
timeout-minutes: 360
steps:
- name: Checkout
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_MEDIUM) }}
if: success()
uses: actions/checkout@v4
- name: Download reports from cache
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success()
uses: actions/cache@v4
with:
# Check available parameters in: https://github.com/actions/cache/blob/main/action.yml
key: reports_${{ github.sha }}_${{ github.run_id }}_${{ github.run_number }}_${{ inputs.name }}_${{ inputs.host_os }}_${{ inputs.type }}_${{ inputs.compiler }}
restore-keys: reports_${{ github.sha }}_${{ github.run_id }}_${{ github.run_number }}_${{ inputs.name }}_${{ inputs.host_os }}_${{ inputs.type }}_${{ inputs.compiler }}
path: |
code_coverage_base.info
code_coverage.info
code_coverage_test.info
code_coverage_filtered.info
- name: Send code climate report
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success()
working-directory: .
env:
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
run: |
# shellcheck disable=SC1091
. scripts/helper_functions.sh && prepareBinaries ${{ github.workspace }};
./test-reporter-latest-linux-amd64 format-coverage -t lcov code_coverage_filtered.info;
./test-reporter-latest-linux-amd64 upload-coverage;
- name: Validate codecov report
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success()
working-directory: .
run: |
curl --retry 5 --retry-delay 2 --connect-timeout 2 --data-binary @codecov.yml https://codecov.io/validate;
- name: Send codecov report
timeout-minutes: ${{ fromJSON(env.GITHUB_STEP_TIMEOUT_SMALL) }}
if: success()
working-directory: .
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
run: |
curl --retry 5 --retry-delay 2 --connect-timeout 2 -s https://codecov.io/bash | bash -s -- -c -F aFlag build_${{ inputs.type }} -v;