1718 lines
71 KiB
YAML
1718 lines
71 KiB
YAML
# Continuous integration: daily Debug on the development branch (push/PR), plus a weekly run.
|
|
# Reusable via workflow_call (build_type: debug | release | both) for releases.
|
|
# Each platform runs as its own parallel job:
|
|
# windows → win32 debug (+ unit tests); windows-release when asked
|
|
# android → android debug; android-release when asked
|
|
# macos → macosx debug (+ unit tests); macos-release when asked
|
|
# ios → ios debug; ios-release when asked
|
|
# linux → linux debug (+ unit tests); linux-release when asked
|
|
# webgpu → webgpu (Emscripten/WASM) release
|
|
#
|
|
# iOS signing (optional repo secrets):
|
|
# IOS_CERTIFICATE_P12_BASE64, IOS_CERTIFICATE_PASSWORD, IOS_DEVELOPMENT_TEAM
|
|
# IOS_PROVISIONING_PROFILE_BASE64 (optional)
|
|
# Without them, iOS builds unsigned (compile-only; cannot install to a device).
|
|
|
|
name: CI
|
|
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
build_type:
|
|
description: debug | release | both
|
|
type: string
|
|
default: debug
|
|
ref:
|
|
description: git ref to check out (release branch or moved tag)
|
|
type: string
|
|
default: ""
|
|
push:
|
|
branches: [dev]
|
|
pull_request:
|
|
branches: [dev]
|
|
schedule:
|
|
# Weekly: Monday 00:00 CST ≈ Sunday 16:00 UTC
|
|
- cron: "0 16 * * 0"
|
|
workflow_dispatch:
|
|
inputs:
|
|
build_type:
|
|
description: debug | release | both
|
|
type: choice
|
|
default: debug
|
|
options: [debug, release, both]
|
|
|
|
concurrency:
|
|
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
env:
|
|
# Single source of truth: repository variables (Settings -> Secrets and
|
|
# variables -> Actions -> Variables), falling back to these defaults.
|
|
VULKAN_VERSION: ${{ vars.VULKAN_VERSION || '1.4.304.1' }}
|
|
# Aligned to the NDK preinstalled on the windows-latest / macos-latest runner
|
|
# images (27.3.13750724), so setup-android downloads nothing extra.
|
|
ANDROID_NDK_VERSION: ${{ vars.ANDROID_NDK_VERSION || '27.3.13750724' }}
|
|
ANDROID_API: ${{ vars.ANDROID_API || '34' }}
|
|
|
|
jobs:
|
|
change-scope:
|
|
name: Classify CI change scope
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 5
|
|
outputs:
|
|
windows: ${{ steps.scope.outputs.windows }}
|
|
android: ${{ steps.scope.outputs.android }}
|
|
macos: ${{ steps.scope.outputs.macos }}
|
|
ios: ${{ steps.scope.outputs.ios }}
|
|
linux: ${{ steps.scope.outputs.linux }}
|
|
asan: ${{ steps.scope.outputs.asan }}
|
|
fuzz: ${{ steps.scope.outputs.fuzz }}
|
|
webgpu: ${{ steps.scope.outputs.webgpu }}
|
|
tools: ${{ steps.scope.outputs.tools }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
fetch-depth: 0
|
|
|
|
- name: Classify changed paths
|
|
id: scope
|
|
env:
|
|
EVENT_NAME: ${{ github.event_name }}
|
|
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
run: |
|
|
if [ "$EVENT_NAME" = "pull_request" ]; then
|
|
python3 scripts/ci_change_scope.py \
|
|
--base "$BASE_SHA" --head "$HEAD_SHA" --github-output "$GITHUB_OUTPUT"
|
|
else
|
|
python3 scripts/ci_change_scope.py --all --github-output "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
# Fast source-only gate for formatting, module boundaries, architecture
|
|
# contracts and the Python scripts that make later CI results trustworthy.
|
|
source-quality:
|
|
name: Source quality
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 20
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
fetch-depth: 0
|
|
|
|
- name: Install source-quality tools
|
|
run: |
|
|
# This job needs Ubuntu packages only. Leave the runner's Chrome
|
|
# installation and repository configuration intact for browser jobs.
|
|
apt_empty_parts="$(mktemp -d)"
|
|
chmod 755 "$apt_empty_parts"
|
|
trap 'rmdir "$apt_empty_parts"' EXIT
|
|
apt_sources=(
|
|
-o "Dir::Etc::sourcelist=$GITHUB_WORKSPACE/.github/apt/ubuntu-noble.sources"
|
|
-o "Dir::Etc::sourceparts=$apt_empty_parts"
|
|
)
|
|
sudo apt-get "${apt_sources[@]}" update
|
|
sudo apt-get "${apt_sources[@]}" install -y clang-format-18
|
|
sudo ln -sf /usr/bin/clang-format-18 /usr/local/bin/clang-format
|
|
python3 -m pip install --user --quiet pillow ruff
|
|
|
|
- name: Check changed lines are clang-format clean
|
|
run: bash .github/scripts/check-format.sh "${{ github.event.pull_request.base.sha || 'origin/dev' }}"
|
|
|
|
- name: Check module dependency layering
|
|
timeout-minutes: 5
|
|
run: python3 scripts/module_depgraph.py --check
|
|
|
|
- name: Check script bindings are documented (all modules)
|
|
timeout-minutes: 5
|
|
run: python3 scripts/check_bindings.py --strict
|
|
|
|
- name: Check binding gap ownership and budget metadata
|
|
timeout-minutes: 5
|
|
run: python3 scripts/check_binding_gap_metadata.py
|
|
|
|
- name: Check declared module layers vs includes
|
|
timeout-minutes: 5
|
|
run: python3 scripts/module_depgraph.py --check-layers
|
|
|
|
- name: Report dependency graph
|
|
timeout-minutes: 5
|
|
if: always()
|
|
run: python3 scripts/module_depgraph.py
|
|
|
|
- name: Check test source manifest
|
|
timeout-minutes: 5
|
|
run: python3 scripts/check_test_manifest.py
|
|
|
|
- name: Check critical return-value diagnostics
|
|
timeout-minutes: 5
|
|
run: python3 scripts/check_nodiscard.py
|
|
|
|
- name: Check release version consistency
|
|
timeout-minutes: 5
|
|
run: python3 scripts/release.py check-versions
|
|
|
|
- name: Check bounded quality debt and profile matrix
|
|
timeout-minutes: 5
|
|
run: make check/quality
|
|
|
|
- name: Audit top-level architecture contracts and changed API shapes
|
|
timeout-minutes: 5
|
|
run: |
|
|
python3 scripts/check_architecture_contracts.py \
|
|
--base "${{ github.event.pull_request.base.sha || github.event.before || 'HEAD^' }}"
|
|
- name: Ruff lint CI and repository scripts
|
|
timeout-minutes: 5
|
|
run: python3 -m ruff check scripts
|
|
|
|
- name: Test CI and repository scripts
|
|
timeout-minutes: 10
|
|
run: python3 -m unittest discover -s scripts/tests -p "test_*.py" -v
|
|
|
|
profile-matrix:
|
|
name: Profile ${{ matrix.profile }}
|
|
# Pull requests already run the toolchain-free profile contract check in
|
|
# source-quality. Full configure/build/smoke coverage belongs to dev
|
|
# pushes, scheduled/manual runs and release workflow calls.
|
|
needs: [source-quality, change-scope]
|
|
if: ${{ needs.source-quality.result == 'success' && github.event_name != 'pull_request' }}
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 90
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
profile: [minimal, 2d, 3d, procgen-core-only, physics-core-only, asset-core-only, headless, server]
|
|
env:
|
|
PROFILE: ${{ matrix.profile }}
|
|
PROFILE_BUILD_ROOT: /tmp/evengine-profile-matrix
|
|
PROFILE_JOBS: 2
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
submodules: recursive
|
|
|
|
- name: Install profile toolchain
|
|
timeout-minutes: 15
|
|
run: |
|
|
# Only Ubuntu indexes are needed for this toolchain.
|
|
test -s /etc/apt/sources.list.d/ubuntu.sources
|
|
sudo apt-get update \
|
|
-o Dir::Etc::sourcelist=/etc/apt/sources.list.d/ubuntu.sources \
|
|
-o Dir::Etc::sourceparts=- -o Acquire::Retries=2
|
|
sudo apt-get install -y --no-install-recommends \
|
|
build-essential cmake ninja-build libvulkan-dev \
|
|
libx11-dev libxi-dev libxcursor-dev libxrandr-dev libxinerama-dev \
|
|
libxext-dev libxss-dev libwayland-dev libxkbcommon-dev
|
|
|
|
- name: Configure profile
|
|
timeout-minutes: 30
|
|
run: make profile/configure
|
|
|
|
- name: Build independent profile smoke target
|
|
timeout-minutes: 35
|
|
run: make profile/build
|
|
|
|
- name: Run independent capability smoke probes
|
|
timeout-minutes: 10
|
|
run: make profile/smoke
|
|
|
|
tool-tests:
|
|
name: Standalone Python tools
|
|
needs: [source-quality, change-scope]
|
|
if: ${{ needs.source-quality.result == 'success' && needs.change-scope.outputs.tools == 'true' }}
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 20
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
|
|
- name: Install Python test dependencies
|
|
timeout-minutes: 10
|
|
run: |
|
|
python3 -m pip install --user --quiet \
|
|
pytest pydantic requests numpy opencv-python-headless pillow ffmpy ruff
|
|
|
|
- name: Ruff lint standalone tools
|
|
timeout-minutes: 5
|
|
run: python3 -m ruff check tools
|
|
|
|
- name: Test asset-pipeline-agent
|
|
timeout-minutes: 5
|
|
run: cd tools/asset-pipeline-agent && python3 -m unittest discover -s tests -v
|
|
|
|
- name: Test scene-qc-agent
|
|
timeout-minutes: 5
|
|
run: cd tools/scene-qc-agent && python3 -m unittest discover -s tests -v
|
|
|
|
- name: Test creative-brain
|
|
timeout-minutes: 5
|
|
run: cd tools/creative-brain && python3 -m pytest -q
|
|
|
|
- name: Test normal-crafter (client)
|
|
timeout-minutes: 5
|
|
run: cd tools/normal-crafter && python3 -m pytest -q test
|
|
|
|
- name: Test story-scene-agent
|
|
timeout-minutes: 5
|
|
run: PYTHONPATH=tools/creative-brain python3 -m pytest -q tools/story-scene-agent/tests
|
|
|
|
- name: Test vision-prefilter
|
|
timeout-minutes: 5
|
|
run: cd tools/vision-prefilter && python3 -m pytest -q test
|
|
|
|
windows:
|
|
name: Windows
|
|
needs: [source-quality, change-scope]
|
|
if: ${{ needs.source-quality.result == 'success' && needs.change-scope.outputs.windows == 'true' && (github.event_name != 'workflow_call' || inputs.build_type == 'debug' || inputs.build_type == 'both') }}
|
|
runs-on: windows-latest
|
|
# This lane builds and tests both Vulkan and native Dawn configurations.
|
|
# A cold Windows runner needs more than 90 minutes for the two independent
|
|
# unit_test builds; keep the per-step limits below as the hang guards.
|
|
timeout-minutes: 180
|
|
env:
|
|
SCCACHE_GHA_ENABLED: "true"
|
|
SCCACHE_GHA_VERSION: evengine-cpp-v1-windows-x64
|
|
# Pull-request cache entries are scoped to refs/pull/*/merge and cannot
|
|
# warm other PRs. Let PRs consume the dev cache without duplicating it.
|
|
SCCACHE_GHA_RW_MODE: ${{ (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/heads/v') || startsWith(inputs.ref, 'v')) && 'READ_WRITE' || 'READ_ONLY' }}
|
|
SCCACHE_DIRECT: "false"
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
submodules: recursive
|
|
|
|
- name: Install build tools
|
|
timeout-minutes: 15
|
|
shell: pwsh
|
|
run: |
|
|
choco install make ninja -y --no-progress
|
|
echo "VS_GENERATOR=Visual Studio 17 2022" >> $env:GITHUB_ENV
|
|
|
|
- name: Setup C/C++ compilation cache
|
|
timeout-minutes: 10
|
|
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
|
|
with:
|
|
version: "v0.16.0"
|
|
|
|
- name: Identify third-party toolchain
|
|
id: third-party-toolchain
|
|
timeout-minutes: 5
|
|
shell: pwsh
|
|
run: |
|
|
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
|
|
$vsRoot = & $vswhere -latest -products * `
|
|
-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 `
|
|
-property installationPath
|
|
$toolsetFile = Join-Path $vsRoot "VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt"
|
|
$toolset = (Get-Content $toolsetFile -Raw).Trim()
|
|
$sdkVersion = (& cmd.exe /d /s /c `
|
|
'cmake\with-msvc.cmd cmd.exe /d /c echo %WindowsSDKVersion%').Trim().TrimEnd('\')
|
|
$cmakeVersion = ((cmake --version | Select-Object -First 1) -split '\s+')[-1]
|
|
"id=msvc-$toolset-winsdk-$sdkVersion-cmake-$cmakeVersion" >> $env:GITHUB_OUTPUT
|
|
|
|
- name: Restore win32 third-party cache
|
|
id: third-party-cache
|
|
timeout-minutes: 15
|
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: build/third-party-binary/win32-debug
|
|
key: third-party-v1-${{ runner.os }}-${{ runner.arch }}-win32-debug-${{ steps.third-party-toolchain.outputs.id }}-${{ hashFiles('cmake/third_party_pin.cmake', 'cmake/third_party_cache_version.txt', 'cmake/patch_third_party.cmake', 'cmake/patches/**', 'cmake/write_third_party_version.cmake') }}
|
|
|
|
- name: Verify restored win32 third-party cache
|
|
if: steps.third-party-cache.outputs.cache-hit == 'true'
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/verify-third-party-cache.sh build/third-party-binary/win32-debug win32 Debug
|
|
|
|
- name: Install Vulkan SDK
|
|
timeout-minutes: 20
|
|
uses: jakoch/install-vulkan-sdk-action@37effcfa045411f8bfbbda26df2fd1b3bf3436fa # v1
|
|
with:
|
|
vulkan_version: ${{ env.VULKAN_VERSION }}
|
|
install_runtime: true
|
|
# Headless Windows runners have no GPU ICD; SwiftShader provides
|
|
# VK_KHR_surface so SDL_WINDOW_VULKAN / unit tests can run.
|
|
install_swiftshader: true
|
|
cache: true
|
|
cache_save_if: ${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' }}
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Setup software Vulkan ICD (SwiftShader)
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/setup-software-vulkan.sh
|
|
|
|
- name: Build win32 debug
|
|
# A PR that changes the third-party patch/cache key must do a full cold
|
|
# dependency plus engine/test build. Recent windows-2025 runners can
|
|
# exceed 40 minutes without any compiler failure, so retain a bounded
|
|
# hang guard while allowing the cold build to finish.
|
|
timeout-minutes: 60
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
tp_args=""
|
|
if [ "${{ steps.third-party-cache.outputs.cache-hit }}" = "true" ]; then
|
|
tp_args="-DEVENGINE_THIRD_PARTY_BINARY_DIR=build/third-party-binary/win32-debug"
|
|
fi
|
|
make build/win32-debug JOBS="${NUMBER_OF_PROCESSORS:-8}" \
|
|
CMAKE_EXTRA_ARGS="-DEVENGINE_ENABLE_STRICT_WARNINGS=ON \
|
|
-DEVENGINE_COMPILER_CACHE=OFF $tp_args"
|
|
|
|
- name: Report C/C++ compilation cache
|
|
if: always()
|
|
timeout-minutes: 5
|
|
run: sccache --show-stats
|
|
|
|
- name: Verify built win32 third-party cache
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/verify-third-party-cache.sh build/third-party-binary/win32-debug win32 Debug
|
|
|
|
- name: Save win32 third-party cache
|
|
if: >-
|
|
steps.third-party-cache.outputs.cache-hit != 'true' &&
|
|
(github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main')
|
|
timeout-minutes: 15
|
|
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: build/third-party-binary/win32-debug
|
|
key: ${{ steps.third-party-cache.outputs.cache-primary-key }}
|
|
|
|
- name: Run win32 unit tests
|
|
timeout-minutes: 40
|
|
# Headless runners have no WASAPI endpoint (0x80070490); OpenAL Soft null backend.
|
|
env:
|
|
ALSOFT_DRIVERS: "null"
|
|
run: make test/win32-debug
|
|
|
|
- name: Capture Vulkan parity artifacts
|
|
timeout-minutes: 10
|
|
env:
|
|
ALSOFT_DRIVERS: "null"
|
|
EVENGINE_RENDER_PARITY_DIR: ${{ github.workspace }}/artifacts/render-parity
|
|
run: ctest --test-dir build/win32-debug -R '^graphics\.backendParity\.' --output-on-failure
|
|
|
|
- name: Configure native Dawn parity lane
|
|
timeout-minutes: 15
|
|
shell: pwsh
|
|
run: |
|
|
cmake\with-msvc.cmd cmake.exe -S . -B build/webgpu-native -G Ninja `
|
|
-DCMAKE_BUILD_TYPE=Debug `
|
|
-DCMAKE_C_COMPILER="$PWD/cmake/msvc-cl.cmd" `
|
|
-DCMAKE_CXX_COMPILER="$PWD/cmake/msvc-cl.cmd" `
|
|
-DEVENGINE_BUILD_PLATFORM=webgpu -DBUILD_PLATFORM=webgpu -DBUILD_TESTING=ON `
|
|
-DEVENGINE_COMPILER_CACHE=SCCACHE `
|
|
-DEVENGINE_THIRD_PARTY_BINARY_DIR="$PWD/build/third-party-binary/win32-debug" `
|
|
-DEVENGINE_DOWNLOAD_SPINE_MODELS=OFF `
|
|
-DEVENGINE_DOWNLOAD_SKINNED_CHARACTER=OFF
|
|
|
|
- name: Verify native Dawn platform selection
|
|
timeout-minutes: 5
|
|
shell: pwsh
|
|
run: |
|
|
$config = Get-Content build/webgpu-native/src/engine/common/config.h -Raw
|
|
$sources = Get-Content build/webgpu-native/src/modules/graphics_src.txt -Raw
|
|
if ($config -notmatch '(?m)^#define EVENGINE_WEBGPU\s*$') {
|
|
throw 'native Dawn build lost EVENGINE_WEBGPU during configuration'
|
|
}
|
|
if ($sources -notmatch 'graphics[/\\]webgpu[/\\]' -or
|
|
$sources -match 'graphics[/\\]vulkan[/\\]') {
|
|
throw 'native Dawn graphics source list does not exclusively select webgpu'
|
|
}
|
|
|
|
- name: Build native Dawn parity lane
|
|
# A cold Dawn/Tint build compiles roughly 2,400 targets and reached
|
|
# 95% only when the former 40-minute guard fired on windows-latest. The
|
|
# full test link reached 2,401/2,403 at 60 minutes as the module matrix
|
|
# grew, so retain a bounded 15-minute link/cache variance margin.
|
|
timeout-minutes: 75
|
|
shell: pwsh
|
|
run: cmake\with-msvc.cmd cmake.exe --build build/webgpu-native --target unit_test -j 8
|
|
|
|
- name: Report native Dawn compilation cache
|
|
if: always()
|
|
timeout-minutes: 5
|
|
run: sccache --show-stats
|
|
|
|
- name: Run native Dawn parity and PCG compute
|
|
# Dawn initialization takes roughly two minutes per isolated test on
|
|
# the Windows software adapter. Keep per-case process isolation while
|
|
# allowing all parity cases plus the PCG compute parity case to complete.
|
|
timeout-minutes: 40
|
|
shell: pwsh
|
|
env:
|
|
ALSOFT_DRIVERS: "null"
|
|
EVENGINE_RENDER_PARITY_DIR: ${{ github.workspace }}/artifacts/render-parity
|
|
run: >-
|
|
ctest --test-dir build/webgpu-native
|
|
-R '^(graphics\.backendParity\..*|gpgpu\.procgen\.transformParity)$'
|
|
--output-on-failure
|
|
|
|
- name: Compare Vulkan and WebGPU parity images
|
|
timeout-minutes: 5
|
|
shell: pwsh
|
|
run: |
|
|
python -m pip install --quiet pillow
|
|
python scripts/compare_render_backends.py `
|
|
artifacts/render-parity/vulkan artifacts/render-parity/webgpu `
|
|
--result-json artifacts/render-parity/ci-result.json
|
|
|
|
- name: Upload render parity artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: render-parity-windows
|
|
path: artifacts/render-parity
|
|
if-no-files-found: warn
|
|
|
|
windows-release:
|
|
name: Windows (Release)
|
|
needs: [source-quality, change-scope]
|
|
if: ${{ needs.source-quality.result == 'success' && needs.change-scope.outputs.windows == 'true' && (inputs.build_type == 'release' || inputs.build_type == 'both') }}
|
|
runs-on: windows-latest
|
|
# A cold Release build took 55 minutes and the process-isolated 3510-case
|
|
# suite reached 3060/3510 at the former 30-minute test guard. Preserve
|
|
# bounded hang detection while budgeting setup, build, and the full suite.
|
|
timeout-minutes: 120
|
|
env:
|
|
SCCACHE_GHA_ENABLED: "true"
|
|
SCCACHE_GHA_VERSION: evengine-cpp-v1-windows-x64-release
|
|
SCCACHE_GHA_RW_MODE: ${{ (startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/heads/v') || startsWith(inputs.ref, 'v')) && 'READ_WRITE' || 'READ_ONLY' }}
|
|
SCCACHE_DIRECT: "false"
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
submodules: recursive
|
|
|
|
- name: Install build tools
|
|
timeout-minutes: 15
|
|
shell: pwsh
|
|
run: |
|
|
choco install make ninja -y --no-progress
|
|
echo "VS_GENERATOR=Visual Studio 17 2022" >> $env:GITHUB_ENV
|
|
|
|
- name: Setup C/C++ compilation cache
|
|
timeout-minutes: 10
|
|
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
|
|
with:
|
|
version: "v0.16.0"
|
|
|
|
- name: Install Vulkan SDK
|
|
timeout-minutes: 20
|
|
uses: jakoch/install-vulkan-sdk-action@37effcfa045411f8bfbbda26df2fd1b3bf3436fa # v1
|
|
with:
|
|
vulkan_version: ${{ env.VULKAN_VERSION }}
|
|
install_runtime: true
|
|
install_swiftshader: true
|
|
cache: true
|
|
cache_save_if: ${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' }}
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Setup software Vulkan ICD (SwiftShader)
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/setup-software-vulkan.sh
|
|
|
|
- name: Build win32 release
|
|
timeout-minutes: 60
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: >-
|
|
make build/win32 JOBS="${NUMBER_OF_PROCESSORS:-8}"
|
|
CMAKE_EXTRA_ARGS="-DEVENGINE_COMPILER_CACHE=SCCACHE -DEVENGINE_ENABLE_ASSERTS=ON"
|
|
|
|
- name: Report C/C++ compilation cache
|
|
if: always()
|
|
timeout-minutes: 5
|
|
run: sccache --show-stats
|
|
|
|
- name: Run win32 release unit tests
|
|
timeout-minutes: 45
|
|
env:
|
|
ALSOFT_DRIVERS: "null"
|
|
run: make test/win32
|
|
|
|
android:
|
|
name: Android
|
|
needs: [source-quality, change-scope]
|
|
if: ${{ needs.source-quality.result == 'success' && needs.change-scope.outputs.android == 'true' && (github.event_name != 'workflow_call' || inputs.build_type == 'debug' || inputs.build_type == 'both') }}
|
|
runs-on: windows-latest
|
|
# A cold NDK build can consume almost the entire 45-minute build-step budget
|
|
# before Gradle packages the finished native library. Keep the step timeout
|
|
# below as the hang guard while leaving enough job budget for setup/cleanup.
|
|
timeout-minutes: 90
|
|
env:
|
|
SCCACHE_GHA_ENABLED: "true"
|
|
SCCACHE_GHA_VERSION: evengine-cpp-v1-android-arm64-debug
|
|
SCCACHE_GHA_RW_MODE: ${{ (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/heads/v') || startsWith(inputs.ref, 'v')) && 'READ_WRITE' || 'READ_ONLY' }}
|
|
SCCACHE_DIRECT: "false"
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
submodules: recursive
|
|
|
|
- name: Install build tools
|
|
timeout-minutes: 15
|
|
shell: pwsh
|
|
run: choco install make ninja -y --no-progress
|
|
|
|
- name: Setup C/C++ compilation cache
|
|
timeout-minutes: 10
|
|
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
|
|
with:
|
|
version: "v0.16.0"
|
|
|
|
- name: Setup Java 17
|
|
timeout-minutes: 10
|
|
uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
|
|
with:
|
|
distribution: temurin
|
|
java-version: "17"
|
|
|
|
- name: Setup Android SDK
|
|
timeout-minutes: 20
|
|
uses: android-actions/setup-android@40fd30fb8d7440372e1316f5d1809ec01dcd3699 # v4.0.1
|
|
with:
|
|
packages: >-
|
|
platform-tools
|
|
platforms;android-${{ env.ANDROID_API }}
|
|
build-tools;${{ env.ANDROID_API }}.0.0
|
|
ndk;${{ env.ANDROID_NDK_VERSION }}
|
|
|
|
- name: Resolve Android SDK / NDK paths
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/setup-android-sdk.sh
|
|
|
|
- name: Write Gradle local.properties
|
|
timeout-minutes: 5
|
|
run: |
|
|
printf 'sdk.dir=%s\n' "$ANDROID_HOME" > platform/android/apk/local.properties
|
|
echo "ANDROID_HOME=$ANDROID_HOME"
|
|
echo "ANDROID_NDK=$ANDROID_NDK"
|
|
test -f "$ANDROID_NDK/build/cmake/android.toolchain.cmake"
|
|
|
|
- name: Build android debug
|
|
timeout-minutes: 60
|
|
run: |
|
|
test -f "$ANDROID_NDK/build/cmake/android.toolchain.cmake"
|
|
make build/android-debug \
|
|
ANDROID_SDK="$ANDROID_SDK" \
|
|
ANDROID_NDK="$ANDROID_NDK" \
|
|
JAVA_HOME="$JAVA_HOME" \
|
|
CMAKE_EXTRA_ARGS="-DEVENGINE_COMPILER_CACHE=SCCACHE" \
|
|
ANDROID_JOBS="${NUMBER_OF_PROCESSORS:-8}"
|
|
|
|
- name: Report C/C++ compilation cache
|
|
if: always()
|
|
timeout-minutes: 5
|
|
run: sccache --show-stats
|
|
|
|
android-release:
|
|
name: Android (Release)
|
|
needs: [source-quality, change-scope]
|
|
if: ${{ needs.source-quality.result == 'success' && needs.change-scope.outputs.android == 'true' && (inputs.build_type == 'release' || inputs.build_type == 'both') }}
|
|
runs-on: windows-latest
|
|
timeout-minutes: 60
|
|
env:
|
|
SCCACHE_GHA_ENABLED: "true"
|
|
SCCACHE_GHA_VERSION: evengine-cpp-v1-android-arm64-release
|
|
SCCACHE_GHA_RW_MODE: ${{ (startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/heads/v') || startsWith(inputs.ref, 'v')) && 'READ_WRITE' || 'READ_ONLY' }}
|
|
SCCACHE_DIRECT: "false"
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
submodules: recursive
|
|
|
|
- name: Install build tools
|
|
timeout-minutes: 15
|
|
shell: pwsh
|
|
run: choco install make ninja -y --no-progress
|
|
|
|
- name: Setup C/C++ compilation cache
|
|
timeout-minutes: 10
|
|
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
|
|
with:
|
|
version: "v0.16.0"
|
|
|
|
- name: Setup Java 17
|
|
timeout-minutes: 10
|
|
uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
|
|
with:
|
|
distribution: temurin
|
|
java-version: "17"
|
|
|
|
- name: Setup Android SDK
|
|
timeout-minutes: 20
|
|
uses: android-actions/setup-android@40fd30fb8d7440372e1316f5d1809ec01dcd3699 # v4.0.1
|
|
with:
|
|
packages: >-
|
|
platform-tools
|
|
platforms;android-${{ env.ANDROID_API }}
|
|
build-tools;${{ env.ANDROID_API }}.0.0
|
|
ndk;${{ env.ANDROID_NDK_VERSION }}
|
|
|
|
- name: Resolve Android SDK / NDK paths
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/setup-android-sdk.sh
|
|
|
|
- name: Write Gradle local.properties
|
|
timeout-minutes: 5
|
|
run: |
|
|
printf 'sdk.dir=%s\n' "$ANDROID_HOME" > platform/android/apk/local.properties
|
|
test -f "$ANDROID_NDK/build/cmake/android.toolchain.cmake"
|
|
|
|
- name: Build android release
|
|
timeout-minutes: 60
|
|
run: |
|
|
test -f "$ANDROID_NDK/build/cmake/android.toolchain.cmake"
|
|
make build/android \
|
|
ANDROID_SDK="$ANDROID_SDK" \
|
|
ANDROID_NDK="$ANDROID_NDK" \
|
|
JAVA_HOME="$JAVA_HOME" \
|
|
CMAKE_EXTRA_ARGS="-DEVENGINE_COMPILER_CACHE=SCCACHE -DEVENGINE_ENABLE_ASSERTS=ON" \
|
|
ANDROID_JOBS="${NUMBER_OF_PROCESSORS:-8}"
|
|
|
|
- name: Report C/C++ compilation cache
|
|
if: always()
|
|
timeout-minutes: 5
|
|
run: sccache --show-stats
|
|
|
|
macos:
|
|
name: macOS
|
|
needs: [source-quality, change-scope]
|
|
if: ${{ needs.source-quality.result == 'success' && needs.change-scope.outputs.macos == 'true' && (github.event_name != 'workflow_call' || inputs.build_type == 'debug' || inputs.build_type == 'both') }}
|
|
runs-on: macos-latest
|
|
timeout-minutes: 120
|
|
env:
|
|
SCCACHE_GHA_ENABLED: "true"
|
|
SCCACHE_GHA_VERSION: evengine-cpp-v1-macos-arm64-debug
|
|
SCCACHE_GHA_RW_MODE: ${{ (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/heads/v') || startsWith(inputs.ref, 'v')) && 'READ_WRITE' || 'READ_ONLY' }}
|
|
SCCACHE_DIRECT: "false"
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
submodules: recursive
|
|
|
|
- name: Install tools
|
|
timeout-minutes: 10
|
|
run: brew install ninja || true
|
|
|
|
- name: Setup C/C++ compilation cache
|
|
timeout-minutes: 10
|
|
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
|
|
with:
|
|
version: "v0.16.0"
|
|
|
|
- name: Install Vulkan SDK (MoltenVK + iOS)
|
|
timeout-minutes: 20
|
|
uses: jakoch/install-vulkan-sdk-action@37effcfa045411f8bfbbda26df2fd1b3bf3436fa # v1
|
|
with:
|
|
vulkan_version: ${{ env.VULKAN_VERSION }}
|
|
cache: true
|
|
cache_save_if: ${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' }}
|
|
destination: ${{ runner.temp }}/VulkanSDK
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Resolve VULKAN_SDK
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/resolve-vulkan-macos.sh "${{ runner.temp }}/VulkanSDK"
|
|
|
|
- name: Build macosx debug
|
|
timeout-minutes: 40
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: >-
|
|
make build/macosx-debug JOBS="$(sysctl -n hw.ncpu)"
|
|
CMAKE_EXTRA_ARGS="-DEVENGINE_COMPILER_CACHE=SCCACHE"
|
|
|
|
- name: Run macosx unit tests
|
|
timeout-minutes: 30
|
|
env:
|
|
ALSOFT_DRIVERS: "null"
|
|
run: make test/macosx-debug
|
|
|
|
- name: Configure native Dawn Metal lane
|
|
timeout-minutes: 20
|
|
run: |
|
|
cmake -S . -B build/webgpu-macos -G Ninja \
|
|
-DCMAKE_BUILD_TYPE=Debug \
|
|
-DEVENGINE_BUILD_PLATFORM=webgpu -DBUILD_PLATFORM=webgpu -DBUILD_TESTING=ON \
|
|
-DEVENGINE_COMPILER_CACHE=SCCACHE \
|
|
-DEVENGINE_THIRD_PARTY_BINARY_DIR="$PWD/build/third-party-binary/macosx-debug" \
|
|
-DEVENGINE_DOWNLOAD_SPINE_MODELS=OFF \
|
|
-DEVENGINE_DOWNLOAD_SKINNED_CHARACTER=OFF
|
|
|
|
- name: Verify native Dawn Metal platform selection
|
|
timeout-minutes: 5
|
|
run: |
|
|
grep -Eq '^#define EVENGINE_WEBGPU[[:space:]]*$' \
|
|
build/webgpu-macos/src/engine/common/config.h
|
|
grep -Eq 'graphics[/\\]webgpu[/\\]' \
|
|
build/webgpu-macos/src/modules/graphics_src.txt
|
|
if grep -Eq 'graphics[/\\]vulkan[/\\]' \
|
|
build/webgpu-macos/src/modules/graphics_src.txt; then
|
|
echo 'native Dawn graphics source list still contains Vulkan' >&2
|
|
exit 1
|
|
fi
|
|
|
|
- name: Build native Dawn Metal lane
|
|
timeout-minutes: 40
|
|
run: cmake --build build/webgpu-macos --target unit_test -j "$(sysctl -n hw.ncpu)"
|
|
|
|
- name: Report C/C++ compilation cache
|
|
if: always()
|
|
timeout-minutes: 5
|
|
run: sccache --show-stats
|
|
|
|
- name: Test native Dawn Metal surface and rendering
|
|
timeout-minutes: 20
|
|
env:
|
|
ALSOFT_DRIVERS: "null"
|
|
run: |
|
|
ctest --test-dir build/webgpu-macos \
|
|
-R '^(graphics\.backendParity\.|RenderSystem3D\.(textureCheckerPixels|lightingAffectsPixels))' \
|
|
--output-on-failure
|
|
|
|
macos-release:
|
|
name: macOS (Release)
|
|
needs: [source-quality, change-scope]
|
|
if: ${{ needs.source-quality.result == 'success' && needs.change-scope.outputs.macos == 'true' && (inputs.build_type == 'release' || inputs.build_type == 'both') }}
|
|
runs-on: macos-latest
|
|
timeout-minutes: 60
|
|
env:
|
|
SCCACHE_GHA_ENABLED: "true"
|
|
SCCACHE_GHA_VERSION: evengine-cpp-v1-macos-arm64-release
|
|
SCCACHE_GHA_RW_MODE: ${{ (startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/heads/v') || startsWith(inputs.ref, 'v')) && 'READ_WRITE' || 'READ_ONLY' }}
|
|
SCCACHE_DIRECT: "false"
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
submodules: recursive
|
|
|
|
- name: Install tools
|
|
timeout-minutes: 10
|
|
run: brew install ninja || true
|
|
|
|
- name: Setup C/C++ compilation cache
|
|
timeout-minutes: 10
|
|
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
|
|
with:
|
|
version: "v0.16.0"
|
|
|
|
- name: Install Vulkan SDK (MoltenVK + iOS)
|
|
timeout-minutes: 20
|
|
uses: jakoch/install-vulkan-sdk-action@37effcfa045411f8bfbbda26df2fd1b3bf3436fa # v1
|
|
with:
|
|
vulkan_version: ${{ env.VULKAN_VERSION }}
|
|
cache: true
|
|
cache_save_if: ${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' }}
|
|
destination: ${{ runner.temp }}/VulkanSDK
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Resolve VULKAN_SDK
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/resolve-vulkan-macos.sh "${{ runner.temp }}/VulkanSDK"
|
|
|
|
- name: Build macosx release
|
|
timeout-minutes: 40
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: >-
|
|
make build/macosx JOBS="$(sysctl -n hw.ncpu)"
|
|
CMAKE_EXTRA_ARGS="-DEVENGINE_COMPILER_CACHE=SCCACHE -DEVENGINE_ENABLE_ASSERTS=ON"
|
|
|
|
- name: Report C/C++ compilation cache
|
|
if: always()
|
|
timeout-minutes: 5
|
|
run: sccache --show-stats
|
|
|
|
- name: Run macosx release unit tests
|
|
timeout-minutes: 30
|
|
env:
|
|
ALSOFT_DRIVERS: "null"
|
|
run: make test/macosx
|
|
|
|
ios:
|
|
name: iOS
|
|
needs: [source-quality, change-scope]
|
|
if: ${{ needs.source-quality.result == 'success' && needs.change-scope.outputs.ios == 'true' && (github.event_name != 'workflow_call' || inputs.build_type == 'debug' || inputs.build_type == 'both') }}
|
|
runs-on: macos-latest
|
|
timeout-minutes: 60
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
submodules: recursive
|
|
|
|
- name: Install tools
|
|
timeout-minutes: 10
|
|
run: brew install ninja || true
|
|
|
|
- name: Install Vulkan SDK (MoltenVK + iOS)
|
|
timeout-minutes: 20
|
|
uses: jakoch/install-vulkan-sdk-action@37effcfa045411f8bfbbda26df2fd1b3bf3436fa # v1
|
|
with:
|
|
vulkan_version: ${{ env.VULKAN_VERSION }}
|
|
cache: true
|
|
cache_save_if: ${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' }}
|
|
destination: ${{ runner.temp }}/VulkanSDK
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Resolve VULKAN_SDK
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/resolve-vulkan-macos.sh "${{ runner.temp }}/VulkanSDK"
|
|
|
|
- name: Setup iOS signing (optional)
|
|
timeout-minutes: 5
|
|
env:
|
|
IOS_CERTIFICATE_P12_BASE64: ${{ secrets.IOS_CERTIFICATE_P12_BASE64 }}
|
|
IOS_CERTIFICATE_PASSWORD: ${{ secrets.IOS_CERTIFICATE_PASSWORD }}
|
|
IOS_DEVELOPMENT_TEAM: ${{ secrets.IOS_DEVELOPMENT_TEAM }}
|
|
IOS_PROVISIONING_PROFILE_BASE64: ${{ secrets.IOS_PROVISIONING_PROFILE_BASE64 }}
|
|
run: bash .github/scripts/setup-ios-signing.sh
|
|
|
|
- name: Build ios debug
|
|
timeout-minutes: 40
|
|
run: |
|
|
set -euo pipefail
|
|
JOBS="$(sysctl -n hw.ncpu)"
|
|
if [ "${IOS_SIGNING:-0}" = "1" ] && [ -n "${IOS_DEVELOPMENT_TEAM:-}" ]; then
|
|
echo "Building signed iOS (team=$IOS_DEVELOPMENT_TEAM)"
|
|
make build/ios-debug \
|
|
IOS_DEVELOPMENT_TEAM="$IOS_DEVELOPMENT_TEAM" \
|
|
ANDROID_JOBS="$JOBS"
|
|
else
|
|
echo "Building unsigned iOS"
|
|
make build/ios-debug \
|
|
IOS_DEVELOPMENT_TEAM= \
|
|
ANDROID_JOBS="$JOBS"
|
|
fi
|
|
|
|
ios-release:
|
|
name: iOS (Release)
|
|
needs: [source-quality, change-scope]
|
|
if: ${{ needs.source-quality.result == 'success' && needs.change-scope.outputs.ios == 'true' && (inputs.build_type == 'release' || inputs.build_type == 'both') }}
|
|
runs-on: macos-latest
|
|
timeout-minutes: 60
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
submodules: recursive
|
|
|
|
- name: Install tools
|
|
timeout-minutes: 10
|
|
run: brew install ninja || true
|
|
|
|
- name: Install Vulkan SDK (MoltenVK + iOS)
|
|
timeout-minutes: 20
|
|
uses: jakoch/install-vulkan-sdk-action@37effcfa045411f8bfbbda26df2fd1b3bf3436fa # v1
|
|
with:
|
|
vulkan_version: ${{ env.VULKAN_VERSION }}
|
|
cache: true
|
|
cache_save_if: ${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' }}
|
|
destination: ${{ runner.temp }}/VulkanSDK
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Resolve VULKAN_SDK
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/resolve-vulkan-macos.sh "${{ runner.temp }}/VulkanSDK"
|
|
|
|
- name: Setup iOS signing (optional)
|
|
timeout-minutes: 5
|
|
env:
|
|
IOS_CERTIFICATE_P12_BASE64: ${{ secrets.IOS_CERTIFICATE_P12_BASE64 }}
|
|
IOS_CERTIFICATE_PASSWORD: ${{ secrets.IOS_CERTIFICATE_PASSWORD }}
|
|
IOS_DEVELOPMENT_TEAM: ${{ secrets.IOS_DEVELOPMENT_TEAM }}
|
|
IOS_PROVISIONING_PROFILE_BASE64: ${{ secrets.IOS_PROVISIONING_PROFILE_BASE64 }}
|
|
run: bash .github/scripts/setup-ios-signing.sh
|
|
|
|
- name: Build ios release
|
|
timeout-minutes: 40
|
|
run: |
|
|
set -euo pipefail
|
|
JOBS="$(sysctl -n hw.ncpu)"
|
|
if [ "${IOS_SIGNING:-0}" = "1" ] && [ -n "${IOS_DEVELOPMENT_TEAM:-}" ]; then
|
|
echo "Building signed iOS (team=$IOS_DEVELOPMENT_TEAM)"
|
|
make build/ios \
|
|
IOS_DEVELOPMENT_TEAM="$IOS_DEVELOPMENT_TEAM" \
|
|
ANDROID_JOBS="$JOBS"
|
|
else
|
|
echo "Building unsigned iOS"
|
|
make build/ios \
|
|
IOS_DEVELOPMENT_TEAM= \
|
|
ANDROID_JOBS="$JOBS"
|
|
fi
|
|
|
|
linux:
|
|
name: Linux
|
|
needs: [source-quality, change-scope]
|
|
if: ${{ needs.source-quality.result == 'success' && needs.change-scope.outputs.linux == 'true' && (github.event_name != 'workflow_call' || inputs.build_type == 'debug' || inputs.build_type == 'both') }}
|
|
runs-on: ubuntu-24.04
|
|
# Full debug build + per-case unit tests + all-example smoke exceeded the
|
|
# previous 60-minute job cap even though each step stayed within its guard.
|
|
timeout-minutes: 90
|
|
env:
|
|
SCCACHE_GHA_ENABLED: "true"
|
|
SCCACHE_GHA_VERSION: evengine-cpp-v1-linux-x64
|
|
# Populate shared caches only from long-lived branches; PR-scoped writes
|
|
# are dead stores after that PR closes and quickly evict reusable entries.
|
|
SCCACHE_GHA_RW_MODE: ${{ (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/heads/v') || startsWith(inputs.ref, 'v')) && 'READ_WRITE' || 'READ_ONLY' }}
|
|
SCCACHE_DIRECT: "false"
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
submodules: recursive
|
|
|
|
- name: Install system packages
|
|
# apt update may consume most of ten minutes while retrying a slow
|
|
# Ubuntu mirror; keep enough time for the package download itself.
|
|
timeout-minutes: 20
|
|
run: |
|
|
# GitHub-hosted ubuntu-24.04 images sometimes pin the retired
|
|
# azure.archive.ubuntu.com mirror, which hangs instead of failing.
|
|
# Normalize to the canonical mirror so apt has a reachable source.
|
|
sudo sed -i -E 's#https?://[^/]*archive\.ubuntu\.com/ubuntu#https://archive.ubuntu.com/ubuntu#g' \
|
|
/etc/apt/apt-mirrors.txt /etc/apt/sources.list /etc/apt/sources.list.d/*.sources 2>/dev/null || true
|
|
printf 'Acquire::Retries "2";\nAcquire::http::Timeout "30";\nAcquire::https::Timeout "30";\n' | \
|
|
sudo tee /etc/apt/apt.conf.d/90eve-timeouts >/dev/null
|
|
sudo pkill -f "unattended-upgrade" || true
|
|
sudo systemctl stop apt-daily.service apt-daily-upgrade.service 2>/dev/null || true
|
|
# Only Ubuntu indexes are needed for this toolchain.
|
|
test -s /etc/apt/sources.list.d/ubuntu.sources
|
|
apt_ok=0
|
|
for i in 1 2 3; do
|
|
timeout 120 sudo apt-get update -o Acquire::Retries=2 \
|
|
-o Dir::Etc::sourcelist=/etc/apt/sources.list.d/ubuntu.sources \
|
|
-o Dir::Etc::sourceparts=- \
|
|
-o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30 && { apt_ok=1; break; }
|
|
[ "$i" -lt 3 ] && sleep 20
|
|
done
|
|
[ "$apt_ok" -eq 1 ] || exit 1
|
|
# Package downloads can exceed the old ten-minute step budget.
|
|
# Keep bounded transport retries and signature/hash verification.
|
|
sudo apt-get install -y --no-install-recommends \
|
|
build-essential cmake ninja-build \
|
|
libx11-dev libxxf86vm-dev libxi-dev libxcursor-dev \
|
|
libxrandr-dev libxinerama-dev libxext-dev libxss-dev \
|
|
libgl1-mesa-dev \
|
|
libbz2-dev libpng-dev \
|
|
libwayland-dev libxkbcommon-dev libasound2-dev \
|
|
mesa-vulkan-drivers vulkan-tools \
|
|
xvfb ffmpeg python3-pil
|
|
|
|
- name: Setup C/C++ compilation cache
|
|
timeout-minutes: 10
|
|
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
|
|
with:
|
|
version: "v0.16.0"
|
|
|
|
- name: Identify third-party toolchain
|
|
id: third-party-toolchain
|
|
timeout-minutes: 5
|
|
run: |
|
|
compiler_target="$(g++ -dumpmachine)"
|
|
compiler_version="$(g++ -dumpfullversion -dumpversion)"
|
|
cmake_version="$(cmake --version | head -n 1 | awk '{print $3}')"
|
|
echo "id=gcc-$compiler_target-$compiler_version-cmake-$cmake_version" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Restore linux third-party cache
|
|
id: third-party-cache
|
|
timeout-minutes: 15
|
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: build/third-party-binary/linux-debug
|
|
key: third-party-v1-ubuntu-24.04-${{ runner.arch }}-linux-debug-${{ steps.third-party-toolchain.outputs.id }}-${{ hashFiles('cmake/third_party_pin.cmake', 'cmake/third_party_cache_version.txt', 'cmake/patch_third_party.cmake', 'cmake/patches/**', 'cmake/write_third_party_version.cmake') }}
|
|
|
|
- name: Verify restored linux third-party cache
|
|
if: steps.third-party-cache.outputs.cache-hit == 'true'
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/verify-third-party-cache.sh build/third-party-binary/linux-debug linux Release
|
|
|
|
- name: Install Vulkan SDK
|
|
timeout-minutes: 20
|
|
uses: jakoch/install-vulkan-sdk-action@37effcfa045411f8bfbbda26df2fd1b3bf3436fa # v1
|
|
with:
|
|
vulkan_version: ${{ env.VULKAN_VERSION }}
|
|
cache: true
|
|
cache_save_if: ${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' }}
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Setup software Vulkan ICD (Lavapipe)
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/setup-software-vulkan.sh
|
|
|
|
- name: Build linux debug
|
|
timeout-minutes: 40
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
tp_args=""
|
|
if [ "${{ steps.third-party-cache.outputs.cache-hit }}" = "true" ]; then
|
|
tp_args="-DEVENGINE_THIRD_PARTY_BINARY_DIR=build/third-party-binary/linux-debug"
|
|
fi
|
|
make build/linux-debug JOBS="$(nproc)" \
|
|
CMAKE_EXTRA_ARGS="-DEVENGINE_ENABLE_STRICT_WARNINGS=ON \
|
|
-DEVENGINE_COMPILER_CACHE=SCCACHE $tp_args"
|
|
|
|
- name: Report C/C++ compilation cache
|
|
if: always()
|
|
timeout-minutes: 5
|
|
run: sccache --show-stats
|
|
|
|
- name: Verify built linux third-party cache
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/verify-third-party-cache.sh build/third-party-binary/linux-debug linux Release
|
|
|
|
- name: Save linux third-party cache
|
|
if: >-
|
|
steps.third-party-cache.outputs.cache-hit != 'true' &&
|
|
(github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main')
|
|
timeout-minutes: 15
|
|
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: build/third-party-binary/linux-debug
|
|
key: ${{ steps.third-party-cache.outputs.cache-primary-key }}
|
|
|
|
- name: Verify resource format fixture integrity
|
|
timeout-minutes: 5
|
|
run: python3 scripts/resource_format_suite.py --report build/resource-format-inventory.json
|
|
|
|
- name: Run linux unit tests
|
|
timeout-minutes: 30
|
|
env:
|
|
ALSOFT_DRIVERS: "null"
|
|
EVENGINE_FORMAT_EXPORT_DIR: "${{ github.workspace }}/build/resource-format-exports"
|
|
run: |
|
|
# CTEST_JOBS=2: Lavapipe renders several window/GPU tests in
|
|
# parallel; -j4 hits a pre-existing race (voxel.render.sceneHillsIsland
|
|
# SEGFAULT) that is not reproducible in isolation.
|
|
xvfb-run -a -s "-screen 0 1280x800x24" make test/linux-debug CTEST_JOBS=2
|
|
|
|
- name: Verify resource test results without skipped or warning-only cases
|
|
timeout-minutes: 20
|
|
env:
|
|
ALSOFT_DRIVERS: "null"
|
|
EVENGINE_FORMAT_EXPORT_DIR: "${{ github.workspace }}/build/resource-format-exports"
|
|
run: |
|
|
xvfb-run -a -s "-screen 0 1280x800x24" python3 scripts/resource_format_suite.py \
|
|
--build-dir build/linux-debug --report build/resource-format-report.json
|
|
|
|
- name: Independently decode resource image exports
|
|
timeout-minutes: 5
|
|
run: |
|
|
/usr/bin/python3 scripts/check_resource_format_exports.py build/resource-format-exports \
|
|
--report build/resource-format-export-report.json
|
|
|
|
- name: Run headless GPU tests without Xvfb
|
|
timeout-minutes: 15
|
|
env:
|
|
ALSOFT_DRIVERS: "null"
|
|
EVENGINE_VIEW_SECONDS: "0.3"
|
|
EVENGINE_PERF_FRAMES: "30"
|
|
run: |
|
|
# The headless GPU suites must run without any display server,
|
|
# proving the headless-vs-window policy in docs/dev/测试覆盖.md §0.
|
|
# (These files never create an SDL window: canvas/device readback only.)
|
|
ctest --test-dir build/linux-debug --output-on-failure -j 2 \
|
|
-R '^bundle/(graphics_font|TextureSampler|gpgpu|tensor|virtualgeometry_gpu|graphics_headless)\.cpp$'
|
|
|
|
- name: Smoke all examples (headless)
|
|
timeout-minutes: 20
|
|
env:
|
|
ALSOFT_DRIVERS: "null"
|
|
run: |
|
|
xvfb-run -a -s "-screen 0 1280x800x24" bash scripts/smoke_examples.sh
|
|
|
|
- name: DevLab developer-experience test (hot reload + DevTools)
|
|
timeout-minutes: 5
|
|
env:
|
|
ALSOFT_DRIVERS: "null"
|
|
run: |
|
|
xvfb-run -a -s "-screen 0 1280x800x24" bash scripts/test_devlab.sh "$PWD/build/linux-debug/src/engine/eve"
|
|
|
|
linux-release:
|
|
name: Linux (Release)
|
|
needs: [source-quality, change-scope]
|
|
if: ${{ needs.source-quality.result == 'success' && needs.change-scope.outputs.linux == 'true' && (inputs.build_type == 'release' || inputs.build_type == 'both') }}
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 60
|
|
env:
|
|
SCCACHE_GHA_ENABLED: "true"
|
|
SCCACHE_GHA_VERSION: evengine-cpp-v1-linux-x64-release
|
|
SCCACHE_GHA_RW_MODE: ${{ (startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/heads/v') || startsWith(inputs.ref, 'v')) && 'READ_WRITE' || 'READ_ONLY' }}
|
|
SCCACHE_DIRECT: "false"
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
submodules: recursive
|
|
|
|
- name: Install system packages
|
|
# Keep parity with the debug lane's full native dependency install.
|
|
timeout-minutes: 15
|
|
run: |
|
|
# GitHub-hosted ubuntu-24.04 images sometimes pin the retired
|
|
# azure.archive.ubuntu.com mirror, which hangs instead of failing.
|
|
# Normalize to the canonical mirror so apt has a reachable source.
|
|
sudo sed -i -E 's#https?://[^/]*archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' \
|
|
/etc/apt/apt-mirrors.txt /etc/apt/sources.list /etc/apt/sources.list.d/*.sources 2>/dev/null || true
|
|
printf 'Acquire::Retries "2";\nAcquire::http::Timeout "30";\nAcquire::https::Timeout "30";\n' | \
|
|
sudo tee /etc/apt/apt.conf.d/90eve-timeouts >/dev/null
|
|
sudo pkill -f "unattended-upgrade" || true
|
|
sudo systemctl stop apt-daily.service apt-daily-upgrade.service 2>/dev/null || true
|
|
# Only Ubuntu indexes are needed for this toolchain.
|
|
test -s /etc/apt/sources.list.d/ubuntu.sources
|
|
apt_ok=0
|
|
for i in 1 2 3; do
|
|
timeout 120 sudo apt-get update -o Acquire::Retries=2 \
|
|
-o Dir::Etc::sourcelist=/etc/apt/sources.list.d/ubuntu.sources \
|
|
-o Dir::Etc::sourceparts=- \
|
|
-o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30 && { apt_ok=1; break; }
|
|
[ "$i" -lt 3 ] && sleep 20
|
|
done
|
|
[ "$apt_ok" -eq 1 ] || exit 1
|
|
sudo apt-get install -y --no-install-recommends \
|
|
build-essential cmake ninja-build \
|
|
libx11-dev libxxf86vm-dev libxi-dev libxcursor-dev \
|
|
libxrandr-dev libxinerama-dev libxext-dev libxss-dev \
|
|
libgl1-mesa-dev \
|
|
libbz2-dev libpng-dev \
|
|
libwayland-dev libxkbcommon-dev libasound2-dev \
|
|
mesa-vulkan-drivers vulkan-tools \
|
|
xvfb
|
|
|
|
- name: Setup C/C++ compilation cache
|
|
timeout-minutes: 10
|
|
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
|
|
with:
|
|
version: "v0.16.0"
|
|
|
|
- name: Install Vulkan SDK
|
|
timeout-minutes: 20
|
|
uses: jakoch/install-vulkan-sdk-action@37effcfa045411f8bfbbda26df2fd1b3bf3436fa # v1
|
|
with:
|
|
vulkan_version: ${{ env.VULKAN_VERSION }}
|
|
cache: true
|
|
cache_save_if: ${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' }}
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Setup software Vulkan ICD (Lavapipe)
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/setup-software-vulkan.sh
|
|
|
|
- name: Build linux release
|
|
timeout-minutes: 40
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: >-
|
|
make build/linux JOBS="$(nproc)"
|
|
CMAKE_EXTRA_ARGS="-DEVENGINE_COMPILER_CACHE=SCCACHE -DEVENGINE_ENABLE_ASSERTS=ON"
|
|
|
|
- name: Report C/C++ compilation cache
|
|
if: always()
|
|
timeout-minutes: 5
|
|
run: sccache --show-stats
|
|
|
|
- name: Run linux release unit tests
|
|
timeout-minutes: 30
|
|
env:
|
|
ALSOFT_DRIVERS: "null"
|
|
run: xvfb-run -a -s "-screen 0 1280x800x24" make test/linux
|
|
|
|
linux-asan:
|
|
name: Linux (ASan+UBSan)
|
|
needs: [source-quality, change-scope]
|
|
if: ${{ needs.source-quality.result == 'success' && needs.change-scope.outputs.asan == 'true' && (github.event_name != 'workflow_call' || inputs.build_type == 'debug' || inputs.build_type == 'both') }}
|
|
runs-on: ubuntu-24.04
|
|
# Allow the 100-minute cold optimized sanitizer build and 90-minute test
|
|
# guards plus dependency/toolchain setup and cache reporting.
|
|
timeout-minutes: 270
|
|
env:
|
|
# Leak detection off: the zeroerr discovery run during the build (and a
|
|
# few tests) allocates process-lifetime state that LeakSanitizer flags;
|
|
# the sanitizer job's value is UAF/OOB/UB, not leaks.
|
|
ASAN_OPTIONS: "detect_leaks=0:halt_on_error=1"
|
|
UBSAN_OPTIONS: "halt_on_error=1:print_stacktrace=1"
|
|
SCCACHE_GHA_ENABLED: "true"
|
|
SCCACHE_GHA_VERSION: evengine-cpp-v1-linux-x64-asan
|
|
SCCACHE_GHA_RW_MODE: ${{ (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/heads/v') || startsWith(inputs.ref, 'v')) && 'READ_WRITE' || 'READ_ONLY' }}
|
|
SCCACHE_DIRECT: "false"
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
submodules: recursive
|
|
|
|
- name: Install system packages
|
|
# Sanitizer jobs use the same full dependency set as the debug lane.
|
|
timeout-minutes: 20
|
|
run: |
|
|
sudo sed -i -E 's#https?://[^/]*archive\.ubuntu\.com/ubuntu#https://archive.ubuntu.com/ubuntu#g' \
|
|
/etc/apt/apt-mirrors.txt /etc/apt/sources.list /etc/apt/sources.list.d/*.sources 2>/dev/null || true
|
|
printf 'Acquire::Retries "2";\nAcquire::http::Timeout "30";\nAcquire::https::Timeout "30";\n' | \
|
|
sudo tee /etc/apt/apt.conf.d/90eve-timeouts >/dev/null
|
|
sudo pkill -f "unattended-upgrade" || true
|
|
sudo systemctl stop apt-daily.service apt-daily-upgrade.service 2>/dev/null || true
|
|
# Only Ubuntu indexes are needed for this toolchain.
|
|
test -s /etc/apt/sources.list.d/ubuntu.sources
|
|
apt_ok=0
|
|
for i in 1 2 3; do
|
|
timeout 120 sudo apt-get update -o Acquire::Retries=2 \
|
|
-o Dir::Etc::sourcelist=/etc/apt/sources.list.d/ubuntu.sources \
|
|
-o Dir::Etc::sourceparts=- \
|
|
-o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30 && { apt_ok=1; break; }
|
|
[ "$i" -lt 3 ] && sleep 20
|
|
done
|
|
[ "$apt_ok" -eq 1 ] || exit 1
|
|
# Package downloads can exceed the old ten-minute step budget.
|
|
# Keep bounded transport retries and signature/hash verification.
|
|
sudo apt-get install -y --no-install-recommends \
|
|
build-essential cmake ninja-build \
|
|
libx11-dev libxxf86vm-dev libxi-dev libxcursor-dev \
|
|
libxrandr-dev libxinerama-dev libxext-dev libxss-dev \
|
|
libgl1-mesa-dev \
|
|
libbz2-dev libpng-dev \
|
|
libwayland-dev libxkbcommon-dev libasound2-dev \
|
|
mesa-vulkan-drivers vulkan-tools \
|
|
xvfb
|
|
|
|
- name: Setup C/C++ compilation cache
|
|
timeout-minutes: 10
|
|
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
|
|
with:
|
|
version: "v0.16.0"
|
|
|
|
- name: Install Vulkan SDK
|
|
timeout-minutes: 20
|
|
uses: jakoch/install-vulkan-sdk-action@37effcfa045411f8bfbbda26df2fd1b3bf3436fa # v1
|
|
with:
|
|
vulkan_version: ${{ env.VULKAN_VERSION }}
|
|
cache: true
|
|
cache_save_if: ${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' }}
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Setup software Vulkan ICD (Lavapipe)
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/setup-software-vulkan.sh
|
|
|
|
- name: Build linux RelWithDebInfo (ASan+UBSan)
|
|
# PRs cannot populate the shared sccache. A new compiler flag set is
|
|
# therefore a cold build; run 34596121051 reached 67% after 55 minutes.
|
|
timeout-minutes: 100
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: >-
|
|
make build/linux-asan JOBS="$(nproc)"
|
|
CMAKE_EXTRA_ARGS="-DEVENGINE_COMPILER_CACHE=SCCACHE"
|
|
|
|
- name: Report C/C++ compilation cache
|
|
if: always()
|
|
timeout-minutes: 5
|
|
run: sccache --show-stats
|
|
|
|
- name: Run linux unit tests (ASan+UBSan)
|
|
# Keep every case process-isolated, but use all CPUs exposed by the
|
|
# GitHub runner instead of hard-coding a runner-size assumption.
|
|
timeout-minutes: 90
|
|
env:
|
|
ALSOFT_DRIVERS: "null"
|
|
run: |
|
|
xvfb-run -a -s "-screen 0 1280x800x24" make test/linux-asan CTEST_JOBS="$(nproc)"
|
|
|
|
linux-coverage:
|
|
name: Linux (Coverage)
|
|
# Coverage is a trend signal rather than a per-PR gate; run weekly and on
|
|
# demand so it does not double CI minutes for every push.
|
|
needs: [source-quality]
|
|
if: ${{ needs.source-quality.result == 'success' && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') }}
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 90
|
|
env:
|
|
SCCACHE_GHA_ENABLED: "true"
|
|
SCCACHE_GHA_VERSION: evengine-cpp-v1-linux-x64-coverage
|
|
SCCACHE_GHA_RW_MODE: ${{ (startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/heads/v') || startsWith(inputs.ref, 'v')) && 'READ_WRITE' || 'READ_ONLY' }}
|
|
SCCACHE_DIRECT: "false"
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
submodules: recursive
|
|
|
|
- name: Install system packages
|
|
# Keep parity with the other full native Linux dependency installs.
|
|
timeout-minutes: 15
|
|
run: |
|
|
sudo sed -i -E 's#https?://[^/]*archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' \
|
|
/etc/apt/apt-mirrors.txt /etc/apt/sources.list /etc/apt/sources.list.d/*.sources 2>/dev/null || true
|
|
printf 'Acquire::Retries "2";\nAcquire::http::Timeout "30";\nAcquire::https::Timeout "30";\n' | \
|
|
sudo tee /etc/apt/apt.conf.d/90eve-timeouts >/dev/null
|
|
sudo pkill -f "unattended-upgrade" || true
|
|
sudo systemctl stop apt-daily.service apt-daily-upgrade.service 2>/dev/null || true
|
|
# Only Ubuntu indexes are needed for this toolchain.
|
|
test -s /etc/apt/sources.list.d/ubuntu.sources
|
|
apt_ok=0
|
|
for i in 1 2 3; do
|
|
timeout 120 sudo apt-get update -o Acquire::Retries=2 \
|
|
-o Dir::Etc::sourcelist=/etc/apt/sources.list.d/ubuntu.sources \
|
|
-o Dir::Etc::sourceparts=- \
|
|
-o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30 && { apt_ok=1; break; }
|
|
[ "$i" -lt 3 ] && sleep 20
|
|
done
|
|
[ "$apt_ok" -eq 1 ] || exit 1
|
|
sudo apt-get install -y --no-install-recommends \
|
|
build-essential cmake ninja-build \
|
|
libx11-dev libxxf86vm-dev libxi-dev libxcursor-dev \
|
|
libxrandr-dev libxinerama-dev libxext-dev libxss-dev \
|
|
libgl1-mesa-dev \
|
|
libbz2-dev libpng-dev \
|
|
libwayland-dev libxkbcommon-dev libasound2-dev \
|
|
mesa-vulkan-drivers vulkan-tools \
|
|
xvfb gcovr
|
|
|
|
- name: Setup C/C++ compilation cache
|
|
timeout-minutes: 10
|
|
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
|
|
with:
|
|
version: "v0.16.0"
|
|
|
|
- name: Install Vulkan SDK
|
|
timeout-minutes: 20
|
|
uses: jakoch/install-vulkan-sdk-action@37effcfa045411f8bfbbda26df2fd1b3bf3436fa # v1
|
|
with:
|
|
vulkan_version: ${{ env.VULKAN_VERSION }}
|
|
cache: true
|
|
cache_save_if: ${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' }}
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Setup software Vulkan ICD (Lavapipe)
|
|
timeout-minutes: 5
|
|
run: bash .github/scripts/setup-software-vulkan.sh
|
|
|
|
- name: Build linux debug (coverage)
|
|
timeout-minutes: 40
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: >-
|
|
make build/linux-coverage JOBS="$(nproc)"
|
|
CMAKE_EXTRA_ARGS="-DEVENGINE_COMPILER_CACHE=SCCACHE"
|
|
|
|
- name: Report C/C++ compilation cache
|
|
if: always()
|
|
timeout-minutes: 5
|
|
run: sccache --show-stats
|
|
|
|
- name: Run linux unit tests (coverage)
|
|
timeout-minutes: 40
|
|
env:
|
|
ALSOFT_DRIVERS: "null"
|
|
run: |
|
|
xvfb-run -a -s "-screen 0 1280x800x24" make test/linux-coverage CTEST_JOBS=2
|
|
|
|
- name: Generate coverage report
|
|
timeout-minutes: 10
|
|
run: |
|
|
gcovr -r . --object-directory build/linux-coverage \
|
|
--exclude 'build/' --exclude 'external/' --exclude 'third-party/' --exclude 'test/' \
|
|
--gcov-ignore-parse-errors \
|
|
--gcov-ignore-errors=no_working_dir_found \
|
|
-x build/linux-coverage/coverage.xml
|
|
gcovr -r . --object-directory build/linux-coverage \
|
|
--exclude 'build/' --exclude 'external/' --exclude 'third-party/' --exclude 'test/' \
|
|
--gcov-ignore-parse-errors \
|
|
--gcov-ignore-errors=no_working_dir_found \
|
|
--html --html-details -o build/linux-coverage/coverage.html
|
|
|
|
- name: Upload coverage artifact
|
|
timeout-minutes: 5
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: linux-coverage
|
|
path: |
|
|
build/linux-coverage/coverage.xml
|
|
build/linux-coverage/coverage.html
|
|
|
|
linux-fuzz:
|
|
name: Linux (zeroerr fuzz)
|
|
needs: [source-quality, change-scope]
|
|
if: ${{ needs.source-quality.result == 'success' && needs.change-scope.outputs.fuzz == 'true' }}
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 20
|
|
env:
|
|
# zeroerr's structured custom mutator retains IRObject allocations for
|
|
# the process lifetime. Keep ASan's UAF/OOB checks without treating that
|
|
# upstream runner behavior as an engine leak.
|
|
ASAN_OPTIONS: "detect_leaks=0:halt_on_error=1"
|
|
UBSAN_OPTIONS: "halt_on_error=1:print_stacktrace=1"
|
|
EVENGINE_FUZZ_RUNS: ${{ github.event_name == 'schedule' && '50000' || '2000' }}
|
|
EVENGINE_FUZZ_SEED: "1"
|
|
SCCACHE_GHA_ENABLED: "true"
|
|
SCCACHE_GHA_VERSION: evengine-cpp-v1-linux-x64-fuzz
|
|
SCCACHE_GHA_RW_MODE: ${{ (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main') && 'READ_WRITE' || 'READ_ONLY' }}
|
|
SCCACHE_DIRECT: "false"
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
submodules: recursive
|
|
|
|
- name: Install fuzz toolchain
|
|
timeout-minutes: 5
|
|
run: |
|
|
# Only Ubuntu indexes are needed for this toolchain.
|
|
test -s /etc/apt/sources.list.d/ubuntu.sources
|
|
sudo apt-get update \
|
|
-o Dir::Etc::sourcelist=/etc/apt/sources.list.d/ubuntu.sources \
|
|
-o Dir::Etc::sourceparts=- -o Acquire::Retries=2
|
|
sudo apt-get install -y --no-install-recommends clang ninja-build
|
|
|
|
- name: Setup C/C++ compilation cache
|
|
timeout-minutes: 10
|
|
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
|
|
with:
|
|
version: "v0.16.0"
|
|
|
|
- name: Build zeroerr JSON fuzz harness
|
|
timeout-minutes: 5
|
|
run: >-
|
|
make build/linux-fuzz JOBS="$(nproc)"
|
|
CMAKE_EXTRA_ARGS="-DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache"
|
|
|
|
- name: Report C/C++ compilation cache
|
|
if: always()
|
|
timeout-minutes: 5
|
|
run: sccache --show-stats
|
|
|
|
- name: Fuzz shared JSON parser
|
|
timeout-minutes: 5
|
|
run: make fuzz/linux JOBS="$(nproc)"
|
|
|
|
- name: Upload reproducer
|
|
if: failure()
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: json-fuzz-reproducer
|
|
path: |
|
|
build/linux-fuzz/crash-*
|
|
build/linux-fuzz/leak-*
|
|
build/linux-fuzz/oom-*
|
|
build/linux-fuzz/timeout-*
|
|
if-no-files-found: ignore
|
|
|
|
webgpu:
|
|
name: WebGPU (WASM)
|
|
needs: [source-quality, change-scope]
|
|
if: ${{ needs.source-quality.result == 'success' && needs.change-scope.outputs.webgpu == 'true' }}
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 60
|
|
env:
|
|
EMSCRIPTEN_VERSION: "6.0.9"
|
|
EMDAWNWEBGPU_RELEASE: "v20260423.175430"
|
|
# Do not add sccache via EM_COMPILER_WRAPPER here: emsdk's Clang commands
|
|
# carry -Xclang flags that sccache v0.16 treats as non-cacheable, adding
|
|
# wrapper overhead without storing any of the engine's object files.
|
|
steps:
|
|
- name: Checkout
|
|
timeout-minutes: 10
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.ref || github.ref }}
|
|
submodules: recursive
|
|
|
|
- name: Install system packages
|
|
timeout-minutes: 10
|
|
run: |
|
|
# GitHub-hosted ubuntu-24.04 images sometimes pin the retired
|
|
# azure.archive.ubuntu.com mirror, which hangs instead of failing.
|
|
# Normalize to the canonical mirror so apt has a reachable source.
|
|
sudo sed -i -E 's#https?://[^/]*archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' \
|
|
/etc/apt/apt-mirrors.txt /etc/apt/sources.list /etc/apt/sources.list.d/*.sources 2>/dev/null || true
|
|
printf 'Acquire::Retries "2";\nAcquire::http::Timeout "30";\nAcquire::https::Timeout "30";\n' | \
|
|
sudo tee /etc/apt/apt.conf.d/90eve-timeouts >/dev/null
|
|
sudo pkill -f "unattended-upgrade" || true
|
|
sudo systemctl stop apt-daily.service apt-daily-upgrade.service 2>/dev/null || true
|
|
# Only Ubuntu indexes are needed for this toolchain.
|
|
test -s /etc/apt/sources.list.d/ubuntu.sources
|
|
apt_ok=0
|
|
for i in 1 2 3; do
|
|
timeout 120 sudo apt-get update -o Acquire::Retries=2 \
|
|
-o Dir::Etc::sourcelist=/etc/apt/sources.list.d/ubuntu.sources \
|
|
-o Dir::Etc::sourceparts=- \
|
|
-o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30 && { apt_ok=1; break; }
|
|
[ "$i" -lt 3 ] && sleep 20
|
|
done
|
|
[ "$apt_ok" -eq 1 ] || exit 1
|
|
sudo apt-get install -y --no-install-recommends \
|
|
git ninja-build python3 python3-pip
|
|
|
|
- name: Install CMake 3.29 (Emscripten is incompatible with CMake 4.x)
|
|
timeout-minutes: 10
|
|
run: |
|
|
python3 -m pip install --user cmake==3.29.6
|
|
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
|
|
|
- name: Restore Emscripten SDK cache
|
|
id: emsdk-cache
|
|
timeout-minutes: 5
|
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: $HOME/emsdk
|
|
key: emsdk-${{ runner.os }}-${{ runner.arch }}-${{ env.EMSCRIPTEN_VERSION }}-${{ env.EMDAWNWEBGPU_RELEASE }}-v1
|
|
|
|
- name: Install Emscripten SDK
|
|
timeout-minutes: 30
|
|
run: |
|
|
if [ "${{ steps.emsdk-cache.outputs.cache-hit }}" = "true" ]; then
|
|
echo "Using cached Emscripten SDK"
|
|
else
|
|
git clone --depth 1 https://github.com/emscripten-core/emsdk.git "$HOME/emsdk"
|
|
fi
|
|
"$HOME/emsdk/emsdk" install "$EMSCRIPTEN_VERSION"
|
|
"$HOME/emsdk/emsdk" activate "$EMSCRIPTEN_VERSION"
|
|
|
|
- name: Acquire and verify immutable WebGPU port
|
|
timeout-minutes: 10
|
|
run: |
|
|
set -euo pipefail
|
|
mkdir -p artifacts/webgpu-dependencies
|
|
archive="artifacts/webgpu-dependencies/emdawnwebgpu.zip"
|
|
url="https://github.com/google/dawn/releases/download/${EMDAWNWEBGPU_RELEASE}/emdawnwebgpu_pkg-${EMDAWNWEBGPU_RELEASE}.zip"
|
|
if ! curl --fail --location --retry 4 --retry-all-errors --retry-delay 5 \
|
|
--output "$archive" "$url"; then
|
|
python3 -c 'from pathlib import Path; from scripts.ci_result import CIResult, FailureKind; CIResult.failure(FailureKind.INFRASTRUCTURE, "WEBGPU_DEPENDENCY_DOWNLOAD_FAILED", "webgpu-dependencies", "failed to download the locked emdawnwebgpu archive after retries").write(Path("artifacts/webgpu-dependencies/ci-result.json"))'
|
|
exit 1
|
|
fi
|
|
python3 scripts/verify_webgpu_dependencies.py \
|
|
--lock cmake/webgpu_dependencies.json \
|
|
--archive "$archive" \
|
|
--emscripten-version "$EMSCRIPTEN_VERSION" \
|
|
--result-json artifacts/webgpu-dependencies/ci-result.json
|
|
|
|
- name: Prewarm Emscripten WebGPU port
|
|
timeout-minutes: 10
|
|
run: |
|
|
set -euo pipefail
|
|
source "$HOME/emsdk/emsdk_env.sh"
|
|
for attempt in 1 2 3; do
|
|
em++ --use-port=emdawnwebgpu -x c++ -c /dev/null \
|
|
-o artifacts/webgpu-dependencies/port-probe.o && exit 0
|
|
[ "$attempt" -lt 3 ] && sleep $((attempt * 10))
|
|
done
|
|
exit 1
|
|
|
|
- name: Upload WebGPU dependency result
|
|
if: always()
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: webgpu-dependency-result
|
|
path: artifacts/webgpu-dependencies/ci-result.json
|
|
if-no-files-found: warn
|
|
|
|
- name: Configure webgpu (Emscripten/WASM)
|
|
timeout-minutes: 15
|
|
run: |
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
source "$HOME/emsdk/emsdk_env.sh"
|
|
emcmake cmake -B build/webgpu-web -G Ninja -DCMAKE_BUILD_TYPE=Release
|
|
|
|
- name: Build webgpu (Emscripten/WASM)
|
|
timeout-minutes: 40
|
|
run: |
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
source "$HOME/emsdk/emsdk_env.sh"
|
|
cmake --build build/webgpu-web --parallel "$(nproc)"
|
|
|
|
- name: Verify webgpu artifacts
|
|
timeout-minutes: 5
|
|
run: |
|
|
test -f build/webgpu-web/src/engine/eve.html
|
|
test -f build/webgpu-web/src/engine/eve.wasm
|
|
ls -lh build/webgpu-web/src/engine/eve.*
|
|
|
|
- name: Capture browser WebGPU frame
|
|
timeout-minutes: 10
|
|
run: |
|
|
python3 -m pip install --quiet pillow
|
|
cd build/webgpu-web/src/engine
|
|
python3 -m http.server 8090 >webgpu-http.log 2>&1 &
|
|
server_pid=$!
|
|
trap 'kill "$server_pid"' EXIT
|
|
google-chrome --headless=new --no-sandbox --disable-gpu-sandbox \
|
|
--enable-unsafe-webgpu --enable-features=Vulkan \
|
|
--use-vulkan=swiftshader --window-size=800,600 \
|
|
--timeout=20000 --screenshot=webgpu-browser.png \
|
|
http://127.0.0.1:8090/eve.html
|
|
python3 "$GITHUB_WORKSPACE/scripts/validate_render_frame.py" webgpu-browser.png
|
|
|
|
- name: Upload browser WebGPU frame
|
|
if: always()
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: webgpu-browser-frame
|
|
path: |
|
|
build/webgpu-web/src/engine/webgpu-browser.png
|
|
build/webgpu-web/src/engine/webgpu-http.log
|
|
if-no-files-found: warn
|
|
|
|
- name: Save Emscripten SDK cache
|
|
# Only refresh on the default branch so per-PR runs restore (free) but
|
|
# never rewrite the cache, keeping churn/eviction of hot caches low.
|
|
if: ${{ steps.emsdk-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/dev' }}
|
|
timeout-minutes: 15
|
|
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: $HOME/emsdk
|
|
key: ${{ steps.emsdk-cache.outputs.cache-primary-key }}
|