Files
oak-editor/.github/workflows/ci.yml
T
Mike-Solar a1268df2f6 ci/cd: fetch x264 from the GitHub mirror (overlay port)
vcpkg's x264 port downloads from code.videolan.org, whose GitLab serves
the archive behind an anti-bot challenge: CI runners hit curl 7/35
(connection/SSL) or 404 at random, so whether a vcpkg install succeeded
was a coin flip. This overlay port is a verbatim copy of the builtin
port at baseline 771b0a2e with vcpkg_from_gitlab swapped for
vcpkg_from_github against mirror/x264 (byte-identical archive, same
SHA512); both workflows now pass --overlay-ports tooling/vcpkg-ports.

Verified locally in debian:12: the port downloaded from
github.com/mirror/x264 and built libx264.a. No other port in the tree
uses code.videolan.org (dav1d/x265 already fetch from GitHub).
2026-09-24 18:28:36 +08:00

645 lines
29 KiB
YAML

name: CI
on:
push:
branches:
- main
pull_request:
branches:
- main
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
# One matrix, seven platforms: the three Linux-family packaging distros
# (Debian 12, Fedora 43, Arch), openKylin on x64 and arm64, macOS and
# Windows. The environments match .github/workflows/cd.yml exactly (same
# container images, same dependency lists, same runner sizes), so a
# "passes CI, fails CD" dependency drift is caught here first.
jobs:
build-test:
name: Build & test (${{ matrix.name }})
runs-on: ${{ matrix.runner }}
# Container entries carry the container as JSON ({"image":...,
# "options":...}); the empty string means "run on the host"
# (actions/runner#265 allows an empty container value).
container: ${{ matrix.container != '' && fromJSON(matrix.container) || '' }}
# The Test step's watchdog caps a hung suite at 30 min; leave a cold
# vcpkg install + full compile room beyond that.
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
include:
- name: Debian
platform: linux
distro: debian
arch: x64
runner: warp-ubuntu-latest-x64-8x
triplet: x64-linux
container: '{"image":"debian:12","options":"--shm-size=8g"}'
- name: Fedora
platform: linux
distro: fedora
arch: x64
runner: warp-ubuntu-latest-x64-8x
triplet: x64-linux
container: '{"image":"fedora:43","options":"--shm-size=8g"}'
- name: Arch
platform: linux
distro: arch
arch: x64
runner: warp-ubuntu-latest-x64-8x
triplet: x64-linux
container: '{"image":"archlinux:latest","options":"--shm-size=8g"}'
- name: openKylin x64
platform: linux
distro: openkylin
arch: x64
runner: warp-ubuntu-latest-x64-8x
triplet: x64-linux
container: '{"image":"openkylin/openkylin:latest","options":"--shm-size=8g"}'
- name: openKylin arm64
platform: linux
distro: openkylin
arch: arm64
runner: warp-ubuntu-latest-arm64-16x
triplet: arm64-linux
container: '{"image":"openkylin/openkylin:latest","options":"--shm-size=8g"}'
- name: macOS
platform: macos
distro: macos
arch: arm64
runner: warp-macos-26-arm64-12x
triplet: arm64-osx
container: ''
- name: Windows
platform: windows
distro: windows
arch: x64
runner: warp-windows-2025-vs2026-x64-32x
triplet: x64-windows
container: ''
steps:
# The container images are bare (Fedora/Arch even lack git);
# checkout and vcpkg need git/curl, and WarpCache needs wget inside
# a container (its README requires it). First step of the job, so
# the package lists are still fresh.
- name: Bootstrap container (git, curl, wget)
if: matrix.container != ''
shell: bash
run: |
case "${{ matrix.distro }}" in
fedora) dnf install -y --setopt=install_weak_deps=False --setopt=max_parallel_downloads=16 git curl wget which ;;
arch) pacman -Sy --noconfirm git curl wget which ;;
debian|openkylin) apt-get update && apt-get install -y git curl ca-certificates wget ;;
esac
- name: Checkout
uses: actions/checkout@v7
with:
# gpui/ is a git submodule; its crates are workspace members of
# their own repo and build as path dependencies of oakapp.
submodules: true
# Taste the disk before the toolchains land: Defender scans every
# file the vcpkg/cargo builds touch (tens of thousands of small
# writes), which dominates a cold Windows build. The runner is an
# ephemeral VM, so the scanner is turned off for the job
# (exclusions are kept as a fallback for images where real-time
# protection cannot be disabled).
- name: Disable Windows Defender scanning
if: matrix.platform == 'windows'
shell: pwsh
run: |
try {
Set-MpPreference -DisableRealtimeMonitoring $true -ErrorAction Stop
Set-MpPreference -DisableScriptScanning $true -ErrorAction SilentlyContinue
Set-MpPreference -DisableArchiveScanning $true -ErrorAction SilentlyContinue
Write-Host "Windows Defender real-time scanning disabled for this job"
} catch {
Write-Host "Windows Defender could not be disabled (non-fatal, falling back to exclusions): $_"
}
foreach ($path in @(
$env:GITHUB_WORKSPACE,
"$env:USERPROFILE\.cargo",
"$env:USERPROFILE\.rustup",
"$env:LOCALAPPDATA\vcpkg"
)) {
Add-MpPreference -ExclusionPath $path -ErrorAction SilentlyContinue
}
try {
Get-MpPreference |
Select-Object DisableRealtimeMonitoring, DisableScriptScanning, ExclusionPath |
Format-List
} catch {
Write-Host "Defender status unavailable: $_"
}
# The containers run as root but Actions sets HOME=/github/home;
# rustup refuses the euid mismatch ("$HOME differs from
# euid-obtained home directory") and would install a toolchain the
# later steps cannot find under the Actions home. Pin the job to
# root's home so rustup/cargo and the toolchain agree.
- name: Pin HOME for rustup
if: matrix.container != ''
shell: bash
run: |
{
echo "HOME=/root"
echo "CARGO_HOME=/root/.cargo"
echo "RUSTUP_HOME=/root/.rustup"
} >> "$GITHUB_ENV"
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
# The Windows build is MSVC-ABI (the runner carries VS 2026):
# vcpkg's FFmpeg and the vendored OCIO build both want it.
toolchain: ${{ matrix.platform == 'windows' && 'stable-x86_64-pc-windows-msvc' || 'stable' }}
# ------------------------------------------------------------------
# System dependencies — one list per distro, byte-for-byte the same
# lists CD uses (see .github/workflows/cd.yml): a package a CD build
# needs cannot be missing here.
# ------------------------------------------------------------------
- name: Install system dependencies (Debian)
if: matrix.distro == 'debian'
shell: bash
run: |
apt-get update
apt-get install -y \
build-essential clang libclang-dev cmake pkg-config nasm \
git curl zip unzip tar python3 dpkg-dev \
libpipewire-0.3-dev libspa-0.2-dev libjack-jackd2-dev \
libasound2-dev libpulse-dev libsndfile1-dev \
libgl1-mesa-dev libgl1-mesa-dri mesa-vulkan-drivers \
libvulkan-dev libxkbcommon-dev libxkbcommon-x11-dev xvfb libdrm-dev \
icc-profiles-free gdb file librsvg2-bin patchelf \
autoconf autoconf-archive automake libtool
- name: Install system dependencies (Fedora)
if: matrix.distro == 'fedora'
shell: bash
run: |
# Fedora 41 is EOL (its mirrors moved to the slow archive), so
# the matrix uses the current release; weak dependencies (docs,
# fonts, optional tooling) are skipped and downloads run wide.
dnf install -y --setopt=install_weak_deps=False \
--setopt=max_parallel_downloads=16 \
gcc gcc-c++ clang clang-devel cmake pkgconf-pkg-config nasm \
git curl zip unzip tar python3 patch xz which \
pipewire-devel jack-audio-connection-kit-devel \
alsa-lib-devel pulseaudio-libs-devel libsndfile-devel \
mesa-libGL-devel mesa-vulkan-drivers \
vulkan-headers vulkan-loader-devel \
libxkbcommon-devel libxkbcommon-x11-devel \
rpm-build librsvg2-tools libdrm-devel \
perl-IPC-Cmd perl-FindBin perl-File-Basename perl-File-Compare \
perl-File-Copy perl-File-Path perl-File-Temp perl-Time-Piece \
xorg-x11-server-Xvfb xorg-x11-xauth gdb file \
autoconf autoconf-archive automake libtool
- name: Install system dependencies (Arch)
if: matrix.distro == 'arch'
shell: bash
run: |
pacman -S --needed --noconfirm \
base-devel clang cmake pkgconf nasm \
git curl zip unzip tar python patch xz which \
pipewire jack2 alsa-lib libpulse libsndfile \
mesa vulkan-headers vulkan-icd-loader \
libxkbcommon libxkbcommon-x11 librsvg libdrm \
xorg-server-xvfb xorg-xauth gdb file \
autoconf autoconf-archive automake libtool
- name: Install system dependencies (openKylin)
if: matrix.distro == 'openkylin'
shell: bash
run: |
apt-get update
apt-get install -y \
build-essential clang libclang-dev cmake pkg-config nasm \
git curl zip unzip tar python3 patch xz-utils dpkg-dev \
libpipewire-0.3-dev libspa-0.2-dev libjack-jackd2-dev \
libasound2-dev libpulse-dev libsndfile1-dev \
libgl1-mesa-dev libgl1-mesa-dri mesa-vulkan-drivers \
libvulkan-dev libxkbcommon-dev libxkbcommon-x11-dev xvfb libdrm-dev \
gdb file patchelf fonts-dejavu-core \
autoconf autoconf-archive automake libtool
- name: Install system dependencies (macOS)
if: matrix.platform == 'macos'
run: |
# Homebrew's pkgconf installs a `pkg-config` symlink, which is
# the name crates/oak-ffmpeg-link/build.rs invokes; nasm is what
# vcpkg's ffmpeg port requires to build (FFmpeg libraries come
# from the vcpkg manifest). librsvg is CD's icon renderer.
brew install cmake pkg-config nasm librsvg autoconf automake libtool autoconf-archive
# ------------------------------------------------------------------
# vcpkg (manifest mode) + caches
# ------------------------------------------------------------------
# Bootstrap a fresh clone rather than leaning on whatever vcpkg the
# image carries: `builtin-baseline`/`overrides` are only honored by
# a recent vcpkg-tool, and every platform must behave alike.
- name: Bootstrap vcpkg
if: matrix.platform != 'windows'
shell: bash
run: |
git clone https://github.com/microsoft/vcpkg.git .cache/vcpkg
.cache/vcpkg/bootstrap-vcpkg.sh -disableMetrics
echo "$PWD/.cache/vcpkg" >> "$GITHUB_PATH"
echo "VCPKG_ROOT=$PWD/.cache/vcpkg" >> "$GITHUB_ENV"
- name: Bootstrap vcpkg (Windows)
if: matrix.platform == 'windows'
shell: pwsh
run: |
git clone https://github.com/microsoft/vcpkg.git "$env:GITHUB_WORKSPACE\.cache\vcpkg"
& "$env:GITHUB_WORKSPACE\.cache\vcpkg\bootstrap-vcpkg.bat" -disableMetrics
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
"$env:GITHUB_WORKSPACE\.cache\vcpkg" >> $env:GITHUB_PATH
"VCPKG_ROOT=$env:GITHUB_WORKSPACE\.cache\vcpkg" >> $env:GITHUB_ENV
# The archives dir is vcpkg's binary cache: a manifest bump then
# rebuilds only what changed. Every run saves under a fresh key (so
# an existing cache is updated, never a save failure) and restores
# the newest matching entry through `restore-keys`. WarpBuild's
# cache service backs the Linux jobs (the GitHub Actions cache
# quota is full); macOS/Windows keep actions/cache.
- name: Restore vcpkg artifacts (WarpCache)
if: matrix.platform == 'linux'
id: vcpkg-cache
uses: WarpBuilds/cache/restore@v2
# A job container does not inherit the runner environment;
# WarpCache authenticates with this token (README: "Running
# inside a container").
env:
WARPBUILD_RUNNER_VERIFICATION_TOKEN: ${{ env.WARPBUILD_RUNNER_VERIFICATION_TOKEN }}
with:
path: |
vcpkg_installed
~/.cache/vcpkg/archives
key: vcpkg-${{ matrix.distro }}-${{ matrix.triplet }}-${{ hashFiles('vcpkg.json') }}-${{ github.run_id }}-${{ github.run_attempt }}
restore-keys: |
vcpkg-${{ matrix.distro }}-${{ matrix.triplet }}-${{ hashFiles('vcpkg.json') }}-
vcpkg-${{ matrix.distro }}-${{ matrix.triplet }}-
- name: Restore vcpkg artifacts (GitHub)
if: matrix.platform != 'linux'
id: vcpkg-cache-github
uses: actions/cache/restore@v6
with:
path: |
vcpkg_installed
~/.cache/vcpkg/archives
~/AppData/Local/vcpkg/archives
key: vcpkg-${{ runner.os }}-${{ matrix.triplet }}-${{ hashFiles('vcpkg.json') }}-${{ github.run_id }}-${{ github.run_attempt }}
restore-keys: |
vcpkg-${{ runner.os }}-${{ matrix.triplet }}-${{ hashFiles('vcpkg.json') }}-
vcpkg-${{ runner.os }}-${{ matrix.triplet }}-
- name: Install dependencies (vcpkg manifest)
if: matrix.platform != 'windows'
shell: bash
run: |
# Source tarballs come from third-party hosts (x264 lives on
# code.videolan.org); a transient connection failure aborts the
# whole install — vcpkg refuses to retry that class of curl
# error — so retry here. vcpkg resumes from its archive and
# download caches, so a repeat attempt is cheap.
for attempt in 1 2 3; do
vcpkg install --triplet ${{ matrix.triplet }} --overlay-triplets tooling/vcpkg-triplets/release --overlay-ports tooling/vcpkg-ports && exit 0
echo "vcpkg install failed (attempt $attempt); retrying"
sleep 15
done
exit 1
- name: Install dependencies (vcpkg manifest, Windows)
if: matrix.platform == 'windows'
shell: pwsh
run: |
for ($i = 1; $i -le 3; $i++) {
vcpkg install --triplet ${{ matrix.triplet }} --overlay-triplets tooling/vcpkg-triplets/release --overlay-ports tooling/vcpkg-ports
if ($LASTEXITCODE -eq 0) { exit 0 }
Write-Host "vcpkg install failed (attempt $i); retrying"
Start-Sleep -Seconds 15
}
exit 1
# Explicit restore/save pair: the old `save-always: true` on the
# combined step does not actually save on a failed job (the action
# deprecation warning), so a run that failed after the install left
# no binary cache and the next run rebuilt FFmpeg from source.
- name: Save vcpkg artifacts (WarpCache)
if: always() && matrix.platform == 'linux'
uses: WarpBuilds/cache/save@v2
env:
WARPBUILD_RUNNER_VERIFICATION_TOKEN: ${{ env.WARPBUILD_RUNNER_VERIFICATION_TOKEN }}
with:
path: |
vcpkg_installed
~/.cache/vcpkg/archives
key: ${{ steps.vcpkg-cache.outputs.cache-primary-key }}
- name: Save vcpkg artifacts (GitHub)
if: always() && matrix.platform != 'linux'
uses: actions/cache/save@v6
with:
path: |
vcpkg_installed
~/.cache/vcpkg/archives
~/AppData/Local/vcpkg/archives
key: ${{ steps.vcpkg-cache-github.outputs.cache-primary-key }}
# ------------------------------------------------------------------
# Build environment
# ------------------------------------------------------------------
# ocio-sys builds a stub bridge unless these are set; the oak-core
# ocioutils tests need the real library.
# tooling/ocio-env.sh: vendored static OCIO (the [patch.crates-io]
# ocio-sys tracks shaloong/ocio-rs main, whose vendored sources build
# on GCC >= 16).
- name: Configure build environment (Linux)
if: matrix.platform == 'linux'
shell: bash
run: |
{
echo "CC=clang"
echo "CXX=clang++"
} >> "$GITHUB_ENV"
bash tooling/ocio-env.sh >> "$GITHUB_ENV"
prefix="$PWD/vcpkg_installed/${{ matrix.triplet }}"
echo "FFMPEG_DIR=$prefix" >> "$GITHUB_ENV"
echo "PKG_CONFIG_PATH=$prefix/lib/pkgconfig" >> "$GITHUB_ENV"
echo "$prefix/tools/pkgconf" >> "$GITHUB_PATH"
# vcpkg's libva/libva-drm are shared libraries that FFmpeg links
# dynamically; without this path the loader picks a system libva
# that may predate symbols FFmpeg uses (undefined vaMapBuffer2).
echo "LD_LIBRARY_PATH=$prefix/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" >> "$GITHUB_ENV"
# The packaging tools resolve the ELF needs through ldd as well
# (dpkg-shlibdeps, linuxdeploy): register the vcpkg libs with the
# dynamic linker so `libva-drm.so.2` is found when a package is
# assembled.
echo "$prefix/lib" > /etc/ld.so.conf.d/oak-vcpkg.conf
ldconfig
- name: Configure build environment (macOS)
if: matrix.platform == 'macos'
shell: bash
run: |
# Vendored static OCIO (same as every non-Windows platform via
# tooling/ocio-env.sh); no OCIO_INSTALL_DIR override.
bash tooling/ocio-env.sh >> "$GITHUB_ENV"
prefix="$PWD/vcpkg_installed/${{ matrix.triplet }}"
echo "FFMPEG_DIR=$prefix" >> "$GITHUB_ENV"
echo "PKG_CONFIG_PATH=$prefix/lib/pkgconfig" >> "$GITHUB_ENV"
echo "$prefix/tools/pkgconf" >> "$GITHUB_PATH"
- name: Configure build environment (Windows)
if: matrix.platform == 'windows'
shell: pwsh
run: |
$prefix = "$env:GITHUB_WORKSPACE\vcpkg_installed\${{ matrix.triplet }}"
"FFMPEG_DIR=$prefix" >> $env:GITHUB_ENV
"PKG_CONFIG_PATH=$prefix\lib\pkgconfig" >> $env:GITHUB_ENV
"$prefix\tools\pkgconf" >> $env:GITHUB_PATH
# The test binaries link vcpkg's dynamic DLLs (ffmpeg and its
# codecs): without this the runner reports STATUS_DLL_NOT_FOUND
# when the first test executable starts.
"$prefix\bin" >> $env:GITHUB_PATH
# Bundled OCIO: ocio-sys' vendored sources build with the MSVC
# toolchain (what they need — the MSYS2 package was the
# workaround, not the preference), so no OCIO_INSTALL_DIR and
# no OCIO_RS_NO_MSVC_INCLUDES anywhere.
"OCIO_RS_ENABLE_REAL=1" >> $env:GITHUB_ENV
"OCIO_RS_LINK=static" >> $env:GITHUB_ENV
# Record the resolved versions in the build log (the manifest
# pins them via overrides + builtin-baseline).
vcpkg list
# ------------------------------------------------------------------
# Cargo caches: whole target/ dir plus ~/.cargo, shared per
# distro+arch (WarpCache for Linux, GitHub for macOS/Windows).
# ------------------------------------------------------------------
- name: Cache cargo artifacts (WarpCache)
if: matrix.platform == 'linux'
uses: WarpBuilds/rust-cache@v2
env:
WARPBUILD_RUNNER_VERIFICATION_TOKEN: ${{ env.WARPBUILD_RUNNER_VERIFICATION_TOKEN }}
with:
shared-key: oak-ci-${{ matrix.distro }}-${{ matrix.arch }}
cache-on-failure: true
- name: Cache cargo artifacts (GitHub)
if: matrix.platform != 'linux'
uses: Swatinem/rust-cache@v2
with:
shared-key: oak-ci-${{ matrix.distro }}-${{ matrix.arch }}
cache-on-failure: true
# ------------------------------------------------------------------
# Build & test
# ------------------------------------------------------------------
# `cargo check` (not build): the Test step links the test binaries
# anyway, and a full build would codegen every workspace crate twice
# (once without and once with cfg(test)).
- name: Build
run: cargo check --workspace --locked
# xvfb + 24-bit screen: the gpui #[gpui::test] tests open real
# windows and render through wgpu on Mesa's software Vulkan
# (lavapipe). The watchdog bounds the step: a deadlocked test
# produces no output and no failure, so after 1800 s it dumps every
# hung process's thread stacks and kills the suite.
- name: Test (Linux)
if: matrix.platform == 'linux'
timeout-minutes: 45
shell: bash
env:
# lavapipe is present in these images: a missing adapter must
# fail the GPU acceptance tests instead of silently skipping
# them (Debian is the x64 reference; the other distros keep the
# historical lenient policy).
OAK_REQUIRE_GPU: ${{ matrix.distro == 'debian' && '1' || '0' }}
run: |
run_suite() {
xvfb-run -a -s "-screen 0 1920x1080x24" cargo test --workspace --locked &
TEST_PID=$!
# The watchdog inherits the step's stdout/stderr; detach it so
# it cannot keep the runner's I/O pipes open after the step
# ends ("WaitDelay expired before I/O complete" otherwise).
(
sleep 1800
echo "::warning::test suite exceeded 1800s; dumping hung-process stacks"
for p in $(pgrep -f 'target/debug/deps/|target/debug/oak-worker'); do
echo "===== thread stacks of pid $p ($(readlink /proc/$p/exe 2>/dev/null)) ====="
gdb -batch -ex 'thread apply all bt' -p "$p" || true
done
pkill -9 -f 'target/debug/deps/' || true
pkill -9 -f 'target/debug/oak-worker' || true
) >/dev/null 2>&1 &
WATCHDOG_PID=$!
wait $TEST_PID
rc=$?
kill $WATCHDOG_PID 2>/dev/null || true
# Reap the watchdog so no child holds the step's pipes.
wait $WATCHDOG_PID 2>/dev/null || true
return $rc
}
# Retry once (same policy as the Windows job): worker-pool
# startup under full-suite parallelism has flaked once
# (full_res_worker_outlives_a_dropped_project: the render
# manager's process dispatcher failed to start while every other
# test passed). A real regression fails both passes.
if ! run_suite; then
echo "first pass failed; retrying once for worker-pool flakes"
run_suite
fi
# The runner's GUI session doubles as the display for the gpui
# #[gpui::test] windows; wgpu renders through Metal.
- name: Test (macOS)
if: matrix.platform == 'macos'
timeout-minutes: 40
run: |
# Retry once (same policy as the other platforms). A hang trips
# the in-script watchdog, which samples the test processes (the
# offending test's native stack lands in the log) before killing
# the suite.
run_suite() {
cargo test --workspace --locked &
TEST_PID=$!
(
sleep 900
echo "::warning::macOS test suite exceeded 900s; sampling hung processes"
for p in $(pgrep -f 'target/debug/deps/' || true); do
echo "===== sample of pid $p ====="
sample "$p" 2 10 2>&1 | head -120 || true
done
pkill -9 -f 'target/debug/deps/' || true
pkill -9 -f 'target/debug/oak-worker' || true
) &
WATCHDOG_PID=$!
wait $TEST_PID
rc=$?
kill $WATCHDOG_PID 2>/dev/null || true
wait $WATCHDOG_PID 2>/dev/null || true
return $rc
}
if ! run_suite; then
echo "first pass failed; retrying once for worker-pool flakes"
run_suite
fi
- name: Test (Windows)
if: matrix.platform == 'windows'
timeout-minutes: 40
shell: pwsh
run: |
cargo test --workspace --locked
if ($LASTEXITCODE -ne 0) {
# Retry once: a few gpui keystroke tests flake on Windows CI —
# a synthetic keystroke is occasionally never delivered (the
# undo/redo pair and a plain 's' toggle both failed once,
# each identically to its pass state). A real regression
# fails both passes.
Write-Host "first pass failed; retrying once for gpui keystroke flakes"
cargo test --workspace --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
}
# ------------------------------------------------------------------
# Failure diagnostics
# ------------------------------------------------------------------
# A crashing (SIGSEGV) test gives no Rust backtrace; rerun the
# crashing test binaries under gdb to capture the native stack.
# `--args` is required — plain `--` makes gdb treat the test args as
# a core file. The extra probes target loader-stage crashes (the
# copier_test SIGSEGV happens inside ld.so's dl_main): si_addr/si_code
# pin down the fault type, the dynsym dump exposes symbols the
# executable exports for interposition, strace shows the last loader
# syscalls, and valgrind catches a corrupting static initializer.
- name: Backtrace on test failure (Debian)
if: failure() && matrix.distro == 'debian'
shell: bash
run: |
apt-get install -y gdb strace valgrind
for name in node_e2e_test suites_test copier_test; do
BIN=$(ls -t target/debug/deps/$name-* | grep -v '\.d$' | head -1)
[ -n "$BIN" ] || continue
echo "===== $BIN ====="
file "$BIN" || true
echo "--- exported defined dynsyms:"
readelf --dyn-syms -W "$BIN" 2>/dev/null | grep -v ' UND ' | tail -n +4 | head -30 || true
echo "--- strace tail:"
strace -f "$BIN" --list 2>&1 | tail -15 || true
echo "--- valgrind tail:"
valgrind -q "$BIN" --list 2>&1 | tail -25 || true
echo "--- gdb:"
xvfb-run -a gdb -batch \
-ex run \
-ex 'bt' \
-ex 'p $_siginfo.si_code' \
-ex 'p/x $_siginfo._sifields._sigfault.si_addr' \
-ex 'x/6i $rip' \
--args "$BIN" --nocapture || true
done
# Same idea for the other distro containers (gdb is installed with
# the system dependencies).
- name: Backtrace on test failure (containers)
if: failure() && matrix.platform == 'linux' && matrix.distro != 'debian'
shell: bash
run: |
for name in oak_render oakapp oak_plugin; do
BIN=$(ls -t target/debug/deps/$name-* 2>/dev/null | grep -v '\.d$' | head -1)
[ -n "$BIN" ] || continue
echo "===== $BIN ====="
timeout 900 xvfb-run -a gdb -batch \
-ex run \
-ex 'thread apply all bt' \
--args "$BIN" || true
done
# A SIGSEGV in a test binary gives no Rust backtrace; Apple's crash
# reports carry the native stack, so surface the newest ones.
- name: Crash reports (macOS)
if: failure() && matrix.platform == 'macos'
run: |
for f in $(ls -t ~/Library/Logs/DiagnosticReports/*.ips 2>/dev/null | head -3); do
echo "===== $f"
head -c 6000 "$f"
echo
done
# ------------------------------------------------------------------
# OFX plugin discovery end-to-end (x64 Linux reference)
# ------------------------------------------------------------------
# Build a minimal but real OFX plugin into a .ofx.bundle, point
# OFX_PLUGIN_PATH at it and let the scan_probe example run the full
# host path (directory scan -> dlopen -> setHost -> load -> describe
# -> register). The assertion is the plugin's registration line; CI
# machines have no system-wide OFX plugins, so the fixture is the
# only discovery.
- name: Build OFX fixture plugin
if: matrix.distro == 'debian'
run: crates/oak-plugin/tests/fixtures/build_fixture.sh .cache/ofx-fixture
- name: Probe OFX plugin discovery
if: matrix.distro == 'debian'
run: |
OFX_PLUGIN_PATH="$PWD/.cache/ofx-fixture" \
cargo run --locked -p oak-plugin --example scan_probe > probe.log 2>&1
grep -q 'type_id=rs.oak.CiTestPlugin' probe.log
# A project carrying a plugin node must survive save/load (the
# serializer resolves plugin types via the dynamic factory).
OAK_OFX_FIXTURE_DIR="$PWD/.cache/ofx-fixture" \
cargo test --locked -p oak-plugin --test ofx_roundtrip