yams/.github/workflows/tests.yml
2026-05-06 21:27:48 -04:00

728 lines
29 KiB
YAML

name: Tests
on:
push:
branches: [main, master, experimental]
pull_request:
branches: [main] # Or your default branch
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
# Keep main-branch history intact so slower matrix lanes still publish evidence.
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
warm:
uses: ./.github/workflows/matrix-warm.yml
with:
build_type: Debug
enable_onnx: false
quality:
name: Static Analysis
runs-on: ubuntu-24.04
timeout-minutes: 20
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: false
- name: Initialize required submodules
shell: bash
run: |
git submodule update --init --depth 1 third_party/sqlite-vec-cpp || true
git submodule update --init --depth 1 third_party/simeon || true
git submodule update --init --depth 1 third_party/symspell || true
- name: Install static analysis tools
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends cppcheck clang-tidy
- name: Run cppcheck (CI profile, changed lines)
shell: bash
run: |
set -euo pipefail
BASE=""
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
BASE="${{ github.event.pull_request.base.sha }}"
elif [[ -n "${{ github.event.before }}" && "${{ github.event.before }}" != "0000000000000000000000000000000000000000" ]]; then
BASE="${{ github.event.before }}"
elif git rev-parse HEAD^ >/dev/null 2>&1; then
BASE="HEAD^"
fi
# Push events can report a `before` SHA that is no longer reachable
# after a force-push/rewrite. In that case, fall back to the checked
# out parent instead of failing before cppcheck runs.
if [[ -n "$BASE" ]] && ! git rev-parse --verify "${BASE}^{commit}" >/dev/null 2>&1; then
echo "Diff base '$BASE' is not available in this checkout; falling back to HEAD^."
if git rev-parse HEAD^ >/dev/null 2>&1; then
BASE="HEAD^"
else
BASE=""
fi
fi
if [[ -n "$BASE" ]]; then
scripts/lint.sh cppcheck --diff "$BASE"
else
scripts/lint.sh cppcheck
fi
- name: Run clang-tidy on changed files (PR only)
if: github.event_name == 'pull_request'
continue-on-error: true # Non-blocking until .clang-tidy baseline is proven on full codebase
shell: bash
run: |
CHANGED=$(git diff --name-only "origin/${{ github.base_ref }}...HEAD" \
| grep -E '\.(cpp|h|hpp|cc|cxx)$' \
| grep -v -E '(third_party|external|subprojects|\.pb\.(h|cc))' \
|| true)
if [ -z "$CHANGED" ]; then
echo "No C++ files changed in this PR."
exit 0
fi
echo "Running clang-tidy on: $CHANGED"
clang-tidy \
--warnings-as-errors='bugprone-*,clang-analyzer-*,concurrency-*' \
$CHANGED \
2>&1 | tee clang-tidy-pr.txt || true
- name: Upload clang-tidy results
if: github.event_name == 'pull_request' && always()
uses: actions/upload-artifact@v4
with:
name: clang-tidy-pr-${{ github.run_number }}
path: clang-tidy-pr.txt
if-no-files-found: ignore
retention-days: 7
tests:
needs: warm
if: ${{ success() }}
name: Tests (${{ matrix.suffix }})
env:
BUILD_DIR: builddir
YAMS_DISABLE_FAISS: 1
strategy:
fail-fast: false
matrix:
include:
- suffix: linux-x86_64
runs_on: ubuntu-24.04
conan_host_profile: ./conan/profiles/host-linux-clang
conan_arch: x86_64
needs_rosetta: false
build_type: Debug
coverage: true
extra_meson_flags: "--buildtype=debug -Dbuild-tests=true -Denable-onnx=disabled"
- suffix: linux-arm64
runs_on: ubuntu-24.04-arm
conan_host_profile: ./conan/profiles/host-linux-clang
conan_arch: armv8
needs_rosetta: false
build_type: Debug
coverage: false
extra_meson_flags: "--buildtype=debug -Dbuild-tests=true -Denable-onnx=disabled"
- suffix: macos-arm64
runs_on: macos-15
conan_host_profile: ./conan/profiles/host-macos-apple-clang
conan_arch: armv8
needs_rosetta: false
build_type: Debug
coverage: false
extra_meson_flags: "--buildtype=debug -Dbuild-tests=true -Denable-onnx=disabled"
- suffix: windows-x86_64
runs_on: windows-latest
conan_host_profile: ./conan/profiles/host-windows-msvc
conan_arch: x86_64
needs_rosetta: false
build_type: Debug
coverage: false
extra_meson_flags: "--buildtype=debug -Dbuild-tests=true -Denable-onnx=disabled"
- suffix: linux-x86_64-asan
runs_on: ubuntu-24.04
conan_host_profile: ./conan/profiles/host-linux-clang
conan_arch: x86_64
needs_rosetta: false
build_type: Debug
coverage: false
extra_meson_flags: "--buildtype=debug -Dbuild-tests=true -Denable-onnx=disabled -Denable-asan=true -Db_sanitize=address -Db_lundef=false"
- suffix: linux-x86_64-ubsan
runs_on: ubuntu-24.04
conan_host_profile: ./conan/profiles/host-linux-clang
conan_arch: x86_64
needs_rosetta: false
build_type: Debug
coverage: false
extra_meson_flags: "--buildtype=debug -Dbuild-tests=true -Denable-onnx=disabled -Denable-ubsan=true -Db_sanitize=undefined -Db_lundef=false"
# TSAN intentionally excluded from CI: boost::asio strand destruction triggers
# a heap-use-after-free that TSAN detects but cannot be suppressed via tsan.suppressions.
# Run TSAN locally with: meson setup builddir-tsan -Denable-tsan=true -Db_sanitize=thread
runs-on: ${{ matrix.runs_on }}
# Allow extra time for safety across runners.
timeout-minutes: 100
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: false # Manual submodule init below (some use SSH URLs)
- name: Skip non-linux-x86_64 matrix entries under act
if: github.actor == 'nektos/act' && matrix.suffix != 'linux-x86_64'
shell: bash
run: |
echo "Skipping matrix entry '${{ matrix.suffix }}' under act."
echo "Act provides Linux container execution only; keep local runs deterministic on linux-x86_64."
exit 0
- name: Free disk space (Linux)
if: runner.os == 'Linux'
uses: jlumbroso/free-disk-space@v1.3.1
with:
tool-cache: false # Keep tools we might need
android: true # ~14GB savings
dotnet: true # ~2.7GB savings
haskell: true # Haskell runtime
large-packages: false # Keep - might need some of these
docker-images: true # Cached docker images
swap-storage: false # Keep swap for large links
- name: Initialize required submodules
shell: bash
run: |
retry_cmd() {
local attempts="$1"
shift
local attempt=1
until "$@"; do
if [ "$attempt" -ge "$attempts" ]; then
return 1
fi
echo "Command failed (attempt ${attempt}/${attempts}): $*" >&2
sleep $((attempt * 5))
attempt=$((attempt + 1))
done
}
# Force HTTPS for GitHub to handle SSH submodule URLs in CI
git config --global url."https://github.com/".insteadOf "git@github.com:"
# Only init submodules required for the build
retry_cmd 4 git submodule update --init --depth 1 third_party/sqlite-vec-cpp
retry_cmd 4 git submodule update --init --depth 1 third_party/simeon
retry_cmd 4 git submodule update --init --depth 1 third_party/symspell
- name: Install system dependencies (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
set -euo pipefail
sudo apt-get update
# Provide system Boost as a fallback per docs/BUILD-GCC.md when CMakeDeps resolution
# is not detected by CMake (module mode will pick this up).
# Install libbenchmark-dev for Google Benchmark support
sudo apt-get install -y --no-install-recommends libboost-all-dev pkg-config libbenchmark-dev xz-utils libomp-18-dev
PYTOOLS_DIR="${RUNNER_TEMP}/yams-python-tools"
python3 -m venv "$PYTOOLS_DIR"
"$PYTOOLS_DIR/bin/python" -m pip install --upgrade pip
"$PYTOOLS_DIR/bin/python" -m pip install --upgrade 'meson==1.4.*' 'ninja==1.11.*'
echo "$PYTOOLS_DIR/bin" >> "$GITHUB_PATH"
export PATH="$PYTOOLS_DIR/bin:$PATH"
echo "meson version: $(meson --version || echo 'missing')"
echo "ninja version: $(ninja --version || echo 'missing')"
echo "Installed system Boost headers/libs for module-mode fallback"
- name: Install Zig (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
set -euo pipefail
ARCH=$(uname -m)
case "$ARCH" in
x86_64) ZIG_ARCH="x86_64" ;;
aarch64) ZIG_ARCH="aarch64" ;;
*) echo "Unsupported architecture: $ARCH"; exit 1 ;;
esac
ZIG_VERSION="0.15.2"
curl -fsSL "https://ziglang.org/download/${ZIG_VERSION}/zig-${ZIG_ARCH}-linux-${ZIG_VERSION}.tar.xz" -o /tmp/zig.tar.xz
sudo tar -xJf /tmp/zig.tar.xz -C /opt
sudo mv /opt/zig-${ZIG_ARCH}-linux-${ZIG_VERSION} /opt/zig
sudo ln -sf /opt/zig/zig /usr/local/bin/zig
rm /tmp/zig.tar.xz
zig version
- name: Install system dependencies (macOS)
if: runner.os == 'macOS'
shell: bash
run: |
set -euo pipefail
for attempt in 1 2 3; do
if brew update; then
break
fi
if [ "$attempt" -eq 3 ]; then
echo "brew update failed after ${attempt} attempts" >&2
exit 1
fi
sleep $((attempt * 10))
done
# Align with release workflow to ensure Meson builds have required toolchain bits.
# Install google-benchmark for benchmark tests, zig for zyp PDF plugin
brew install pkg-config cmake ccache boost google-benchmark zig || true
PYTOOLS_DIR="${RUNNER_TEMP}/yams-python-tools"
python3 -m venv "$PYTOOLS_DIR"
"$PYTOOLS_DIR/bin/python" -m pip install --upgrade pip
"$PYTOOLS_DIR/bin/python" -m pip install --upgrade 'meson==1.4.*' 'ninja==1.11.*'
echo "$PYTOOLS_DIR/bin" >> "$GITHUB_PATH"
export PATH="$PYTOOLS_DIR/bin:$PATH"
echo "meson version: $(meson --version || echo 'missing')"
echo "ninja version: $(ninja --version || echo 'missing')"
echo "zig version: $(zig version || echo 'missing')"
- name: Install system dependencies (Windows)
if: runner.os == 'Windows'
shell: bash
run: |
set -euo pipefail
PYTOOLS_DIR="${RUNNER_TEMP}/yams-python-tools"
python -m venv "$PYTOOLS_DIR"
"$PYTOOLS_DIR/Scripts/python.exe" -m pip install --upgrade pip
"$PYTOOLS_DIR/Scripts/python.exe" -m pip install --upgrade 'meson==1.4.*' 'ninja==1.11.*'
echo "$PYTOOLS_DIR/Scripts" >> "$GITHUB_PATH"
export PATH="$PYTOOLS_DIR/Scripts:$PATH"
echo "meson version: $(meson --version || echo 'missing')"
echo "ninja version: $(ninja --version || echo 'missing')"
# Clean stale builddir to avoid Meson version incompatibility
if [ -d "${{ env.BUILD_DIR }}" ]; then
echo "Removing stale builddir to ensure clean Meson configuration"
rm -rf "${{ env.BUILD_DIR }}"
fi
- name: Install Zig (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$zigVersion = "0.15.2"
$zigUrl = "https://ziglang.org/download/${zigVersion}/zig-x86_64-windows-${zigVersion}.zip"
$zigZip = "$env:TEMP\zig.zip"
$zigDir = "C:\zig"
Invoke-WebRequest -Uri $zigUrl -OutFile $zigZip
Expand-Archive -Path $zigZip -DestinationPath $zigDir -Force
Move-Item "$zigDir\zig-x86_64-windows-${zigVersion}\*" $zigDir -Force
Remove-Item "$zigDir\zig-x86_64-windows-${zigVersion}" -Recurse -ErrorAction SilentlyContinue
$env:PATH = "$zigDir;$env:PATH"
"$zigDir" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
zig version
- name: Cache Conan packages
id: cache_conan
uses: actions/cache@v4
with:
path: |
~/.conan2/p
~/.conan2/r
~/.conan2/recipes
~/.conan2/metadata
~/.conan2/s
key: conan2-${{ runner.os }}-${{ matrix.suffix }}-${{ hashFiles('conanfile.py', 'conan/profiles/**') }}
restore-keys: |
conan2-${{ runner.os }}-${{ matrix.suffix }}-
conan2-${{ runner.os }}-linux-x86_64-
conan2-${{ runner.os }}-
- name: Conan cache diagnostics
shell: bash
run: |
echo "Conan cache hit: ${{ steps.cache_conan.outputs.cache-hit }}"
du -sh ~/.conan2/p 2>/dev/null || true
ls ~/.conan2/r 2>/dev/null | head || true
- name: Cache ccache
uses: actions/cache@v4
with:
path: |
~/.cache/ccache
~/.ccache
key: ccache-${{ runner.os }}-${{ matrix.suffix }}-${{ hashFiles('conanfile.py', 'meson.build', 'meson_options.txt') }}
restore-keys: |
ccache-${{ runner.os }}-${{ matrix.suffix }}-
ccache-${{ runner.os }}-linux-x86_64-
ccache-${{ runner.os }}-
- name: Install Conan (latest)
shell: bash
run: |
set -euo pipefail
PYTOOLS_DIR="${RUNNER_TEMP}/yams-python-tools"
if [ "$RUNNER_OS" = "Windows" ]; then
VENV_PYTHON="$PYTOOLS_DIR/Scripts/python.exe"
TOOL_BIN="$PYTOOLS_DIR/Scripts"
if [ ! -f "$VENV_PYTHON" ]; then
python -m venv "$PYTOOLS_DIR"
fi
else
VENV_PYTHON="$PYTOOLS_DIR/bin/python"
TOOL_BIN="$PYTOOLS_DIR/bin"
if [ ! -x "$VENV_PYTHON" ]; then
python3 -m venv "$PYTOOLS_DIR"
fi
fi
"$VENV_PYTHON" -m pip install --upgrade pip
"$VENV_PYTHON" -m pip install --upgrade 'conan==2.21.*' 'meson==1.4.*' 'ninja==1.11.*'
echo "$TOOL_BIN" >> "$GITHUB_PATH"
export PATH="$TOOL_BIN:$PATH"
conan --version
meson --version
ninja --version
mkdir -p ~/.conan2
cp .conan/global.conf ~/.conan2/global.conf 2>/dev/null || true
# Continue directly with build/test steps (single job path)
- name: Install optional system dependencies
if: runner.os == 'Linux'
shell: bash
run: |
set -euo pipefail
sudo apt-get install -y --no-install-recommends liburing-dev libarchive-dev libtag1-dev ccache || true
echo "Optional packages installed (best-effort)."
- name: Setup ccache env
shell: bash
run: |
set -euo pipefail
echo "CCACHE_DIR=$HOME/.cache/ccache" >> $GITHUB_ENV
echo "CCACHE_BASEDIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV
echo "CCACHE_COMPRESS=1" >> $GITHUB_ENV
echo "CCACHE_MAXSIZE=5G" >> $GITHUB_ENV
echo "CCACHE_SLOPPINESS=time_macros,include_file_mtime,include_file_ctime,file_macro" >> $GITHUB_ENV
ccache -p 2>/dev/null || true
ccache -z 2>/dev/null || true
# Conan already installed above
- name: Setup Conan Profile
shell: bash
run: |
conan profile detect --force
sed -i 's/compiler.cppstd=.*/compiler.cppstd=20/' ~/.conan2/profiles/default || true
echo "Conan profile configured:" >&2
conan profile show >&2
- name: Detect clang version (log only)
shell: bash
run: |
set -euo pipefail
if command -v clang++ >/dev/null 2>&1; then
RAW_VER=$(clang++ --version | sed -n 's/.*version \([0-9][0-9]*\).*/\1/p' | head -1 || true)
elif command -v clang >/dev/null 2>&1; then
RAW_VER=$(clang --version | sed -n 's/.*version \([0-9][0-9]*\).*/\1/p' | head -1 || true)
else
RAW_VER=""
fi
if [ -n "$RAW_VER" ]; then
echo "Detected clang major: $RAW_VER"
else
echo "WARNING: clang not found; default profile may resolve gcc instead" >&2
fi
- name: Clean corrupted Conan cache if needed
shell: bash
run: |
if ! conan list "*" 2>/dev/null;
then
echo "Conan cache appears corrupted, cleaning locks and temp files..."
conan cache clean --locks --temp 2>/dev/null || true
echo "Conan cache locks/temp cleaned"
fi
- name: Tune Conan client (parallel downloads)
shell: bash
run: |
set -euo pipefail
CONF_FILE="$HOME/.conan2/global.conf"
LINE="core.download:parallel=8"
mkdir -p "$(dirname "$CONF_FILE")"
if [ -f "$CONF_FILE" ]; then
TMP_FILE="$(mktemp)"
awk -v line="$LINE" '
BEGIN { replaced = 0 }
/^core.download:parallel=/ { if (!replaced) { print line; replaced = 1 } ; next }
{ print }
END { if (!replaced) print line }
' "$CONF_FILE" > "$TMP_FILE"
mv "$TMP_FILE" "$CONF_FILE"
else
printf '%s\n' "$LINE" > "$CONF_FILE"
fi
echo "Configured $LINE in $CONF_FILE"
grep -n '^core.download:parallel=' "$CONF_FILE" || true
conan config show core.download:parallel 2>/dev/null || true
conan --version
- name: Configure and Build with Meson (Unix)
id: build_unix
if: runner.os != 'Windows'
shell: bash
run: |
set -euo pipefail
ARCH_PREFIX=""
if [ "${{ matrix.needs_rosetta }}" = "true" ]; then
softwareupdate --install-rosetta --agree-to-license || true
ARCH_PREFIX="arch -x86_64"
fi
# Keep AF_UNIX socket path short on Linux to avoid sun_path length limits
if [ "$RUNNER_OS" = "Linux" ]; then
XDG_RUNTIME_DIR="/run/user/$(id -u)"
mkdir -p "$XDG_RUNTIME_DIR" || true
echo "XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR" >> "$GITHUB_ENV"
fi
# Use setup.sh with CI environment variables for consistent build configuration
export YAMS_CONAN_HOST_PROFILE="${{ matrix.conan_host_profile }}"
export YAMS_CONAN_ARCH="${{ matrix.conan_arch }}"
export YAMS_EXTRA_MESON_FLAGS="${{ matrix.extra_meson_flags }}"
export YAMS_ENABLE_MOBILE_BINDINGS=false
# Disable TSAN in CI - boost::asio strand destruction causes heap-use-after-free
# that TSAN detects but cannot be suppressed. Run TSAN locally for development.
export ENABLE_TSAN=false
chmod +x setup.sh
$ARCH_PREFIX ./setup.sh Debug
# Source Conan build env so meson compile uses the same meson version
# that setup.sh used for meson setup (Conan provides meson 1.10.x which
# creates build.dat incompatible with older system meson).
CONAN_BUILD_ENV="builddir/build-debug/conan/conanbuild.sh"
if [ -f "${CONAN_BUILD_ENV}" ]; then set +u; source "${CONAN_BUILD_ENV}"; set -u; fi
$ARCH_PREFIX meson compile -C builddir
- name: Configure and Build with Meson (Windows)
id: build_windows
if: runner.os == 'Windows'
shell: pwsh
env:
YAMS_CONAN_HOST_PROFILE: ${{ matrix.conan_host_profile }}
YAMS_CONAN_ARCH: ${{ matrix.conan_arch }}
YAMS_EXTRA_MESON_FLAGS: ${{ matrix.extra_meson_flags }}
YAMS_ENABLE_MOBILE_BINDINGS: "false"
run: |
.\setup.ps1 Debug
# Diagnostic for Windows Boost lookup. Reads BOOST_* env vars set by
# setup.ps1 (persisted to GITHUB_ENV) and lists the actual Conan boost
# lib filenames so we can pattern-match meson's expected naming if the
# build above fails. continue-on-error + always() so it never blocks.
- name: (diag) Boost env + Conan lib layout (Windows)
if: runner.os == 'Windows' && always()
shell: pwsh
continue-on-error: true
run: |
Write-Host "BOOST_ROOT=$env:BOOST_ROOT"
Write-Host "BOOST_INCLUDEDIR=$env:BOOST_INCLUDEDIR"
Write-Host "BOOST_LIBRARYDIR=$env:BOOST_LIBRARYDIR"
if ($env:BOOST_LIBRARYDIR -and (Test-Path $env:BOOST_LIBRARYDIR)) {
Write-Host "--- $env:BOOST_LIBRARYDIR contents (boost_*) ---"
Get-ChildItem $env:BOOST_LIBRARYDIR -Filter 'boost_*' | Select Name | Format-Table -AutoSize | Out-String
Write-Host "--- $env:BOOST_LIBRARYDIR contents (libboost_*) ---"
Get-ChildItem $env:BOOST_LIBRARYDIR -Filter 'libboost_*' -ErrorAction SilentlyContinue | Select Name | Format-Table -AutoSize | Out-String
}
- name: ccache stats (post-build)
if: always() && runner.os != 'Windows'
shell: bash
run: |
set +e
ccache -s 2>/dev/null || true
du -sh "${CCACHE_DIR:-$HOME/.cache/ccache}" 2>/dev/null || true
# - name: Check mobile ABI surface
# shell: bash
# run: |
# set -euo pipefail
# LIB_PATH=$(find "${{ env.BUILD_DIR }}" -type f \( -name 'libyams_mobile*.so' -o -name 'libyams_mobile*.dylib' -o -name 'yams_mobile.dll' \) | head -n1)
# if [ -z "$LIB_PATH" ]; then
# echo "libyams_mobile shared library not found under ${{ env.BUILD_DIR }}" >&2
# exit 1
# fi
# scripts/ci/check_mobile_abi.sh "$LIB_PATH"
- name: Run Tests with Meson (Unix)
id: meson_tests_unix
if: ${{ !matrix.needs_rosetta && runner.os != 'Windows' }}
shell: bash
continue-on-error: true
env:
YAMS_TEST_SAFE_SINGLE_INSTANCE: "1"
YAMS_SQLITE_MINIMAL_PRAGMAS: "1"
YAMS_SQLITE_VEC_INIT_TIMEOUT_MS: "1500"
YAMS_SQLITE_BUSY_TIMEOUT_MS: "1000"
YAMS_VDB_IN_MEMORY: "1"
YAMS_SQLITE_VEC_SKIP_INIT: "1"
YAMS_DISABLE_VECTORS: "1"
YAMS_TESTING: "1"
run: |
set -euo pipefail
if [ "$RUNNER_OS" = "Linux" ]; then
mkdir -p "${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" || true
echo "Using XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
fi
CONAN_BUILD_ENV=""
for candidate in \
"${{ env.BUILD_DIR }}/build-debug/conan/conanbuild.sh" \
"${{ env.BUILD_DIR }}/conan/conanbuild.sh"
do
if [ -f "$candidate" ]; then
CONAN_BUILD_ENV="$candidate"
break
fi
done
if [ -n "$CONAN_BUILD_ENV" ]; then
set +u
source "$CONAN_BUILD_ENV"
set -u
fi
# Run unit and integration tests (TSAN disabled in CI)
meson test -C ${{ env.BUILD_DIR }} --suite unit --suite integration --print-errorlogs --timeout-multiplier 2
- name: Run Tests with Meson (Windows)
id: meson_tests_windows
if: runner.os == 'Windows'
shell: pwsh
continue-on-error: true
env:
YAMS_TEST_SAFE_SINGLE_INSTANCE: "1"
YAMS_SQLITE_MINIMAL_PRAGMAS: "1"
YAMS_SQLITE_VEC_INIT_TIMEOUT_MS: "1500"
YAMS_SQLITE_BUSY_TIMEOUT_MS: "1000"
YAMS_VDB_IN_MEMORY: "1"
YAMS_SQLITE_VEC_SKIP_INIT: "1"
YAMS_DISABLE_VECTORS: "1"
YAMS_TESTING: "1"
run: |
$ErrorActionPreference = "Stop"
$conanBuildPs1 = $null
$candidates = @(
(Join-Path "${{ env.BUILD_DIR }}" "build-debug/conan/conanbuild.ps1"),
(Join-Path "${{ env.BUILD_DIR }}" "conan/conanbuild.ps1")
)
foreach ($candidate in $candidates) {
if (Test-Path $candidate) {
$conanBuildPs1 = $candidate
break
}
}
if ($conanBuildPs1) {
. $conanBuildPs1
}
# Run only unit and integration tests (exclude bench, stress, daemon-long, etc.)
meson test -C ${{ env.BUILD_DIR }} --suite unit --suite integration --print-errorlogs --timeout-multiplier 2
- name: Run Tests with Meson (Rosetta x86_64)
id: meson_tests_rosetta
if: ${{ matrix.needs_rosetta }}
shell: bash
continue-on-error: true
env:
YAMS_TEST_SAFE_SINGLE_INSTANCE: "1"
YAMS_SQLITE_MINIMAL_PRAGMAS: "1"
YAMS_SQLITE_VEC_INIT_TIMEOUT_MS: "1500"
YAMS_SQLITE_BUSY_TIMEOUT_MS: "1000"
YAMS_VDB_IN_MEMORY: "1"
YAMS_SQLITE_VEC_SKIP_INIT: "1"
YAMS_DISABLE_VECTORS: "1"
YAMS_TESTING: "1"
run: |
set -euo pipefail
# Ensure Rosetta is present (idempotent)
softwareupdate --install-rosetta --agree-to-license || true
CONAN_BUILD_ENV=""
for candidate in \
"${{ env.BUILD_DIR }}/build-debug/conan/conanbuild.sh" \
"${{ env.BUILD_DIR }}/conan/conanbuild.sh"
do
if [ -f "$candidate" ]; then
CONAN_BUILD_ENV="$candidate"
break
fi
done
if [ -n "$CONAN_BUILD_ENV" ]; then
set +u
source "$CONAN_BUILD_ENV"
set -u
fi
# Run only unit and integration tests (exclude bench, stress, daemon-long, etc.)
arch -x86_64 meson test -C ${{ env.BUILD_DIR }} --suite unit --suite integration --print-errorlogs --timeout-multiplier 2
- name: Upload build and test logs (artifacts)
if: ${{ always() && (steps.build_unix.outcome == 'failure' || steps.build_windows.outcome == 'failure' || steps.meson_tests_unix.outcome == 'failure' || steps.meson_tests_windows.outcome == 'failure' || steps.meson_tests_rosetta.outcome == 'failure') }}
uses: actions/upload-artifact@v4
with:
name: logs-${{ matrix.suffix }}-${{ github.run_number }}
path: |
${{ env.BUILD_DIR }}/meson-logs/
${{ env.BUILD_DIR }}/meson-info/
${{ env.BUILD_DIR }}/meson-logs/testlog.txt
${{ env.BUILD_DIR }}/**/conan-install/**/*.log
${{ env.BUILD_DIR }}/**/conan*.log
if-no-files-found: ignore
retention-days: 14
- name: Job Summary (artifacts link)
if: always()
shell: bash
run: |
echo "### Artifacts" >> "$GITHUB_STEP_SUMMARY"
echo "[View artifacts for this run]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)" >> "$GITHUB_STEP_SUMMARY"
- name: Enforce test failure
if: ${{ always() && (steps.meson_tests_unix.outcome == 'failure' || steps.meson_tests_windows.outcome == 'failure' || steps.meson_tests_rosetta.outcome == 'failure') }}
shell: bash
run: |
echo "Meson tests reported failures; enforcing job failure." >&2
exit 1
- name: Generate Coverage Report
if: matrix.coverage == true
shell: bash
run: |
pip3 install gcovr
gcovr --root "$GITHUB_WORKSPACE" \
--exclude 'tests/*' \
--exclude '_deps/*' \
--exclude 'build/*' \
--html --html-details \
--output "${{ env.BUILD_DIR }}/coverage.html"
gcovr --root "$GITHUB_WORKSPACE" \
--exclude 'tests/*' \
--exclude '_deps/*' \
--exclude 'build/*' \
--xml --output "${{ env.BUILD_DIR }}/coverage.xml"
- name: Upload Coverage Report
if: matrix.coverage == true
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: ${{ env.BUILD_DIR }}/coverage.html
if-no-files-found: error
retention-days: 5
- name: Upload Coverage XML
if: matrix.coverage == true
uses: actions/upload-artifact@v4
with:
name: coverage-xml
path: ${{ env.BUILD_DIR }}/coverage.xml
if-no-files-found: error
retention-days: 5
- name: Upload Benchmark Results
if: github.actor != 'nektos/act' && matrix.conan_arch == 'x86_64'
uses: actions/upload-artifact@v4
with:
name: benchmark-results-linux-hosted-yams
path: |
${{ env.BUILD_DIR }}/bench_results/**/*.json
${{ env.BUILD_DIR }}/bench_results/*.json
if-no-files-found: ignore
retention-days: 5