Skip to content

feat(compat.openblas): Windows support (import-lib + runtime DLL) + W… #156

feat(compat.openblas): Windows support (import-lib + runtime DLL) + W…

feat(compat.openblas): Windows support (import-lib + runtime DLL) + W… #156

Workflow file for this run

name: validate
on:
pull_request:
paths: ["pkgs/**/*.lua", "tests/**", "README.md", ".github/workflows/validate.yml"]
push:
branches: [main]
schedule:
# nightly full regression — exercises every smoke suite regardless of diff
- cron: "0 6 * * *"
workflow_dispatch:
env:
# Bumped to 0.0.73: carries Windows runtime-DLL deployment, required by the
# compat.openblas Windows recipe (bin/libopenblas.dll staged beside the .exe).
MCPP_VERSION: "0.0.73"
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install lua
run: sudo apt-get install -y --no-install-recommends lua5.4
- name: Lint package descriptors
run: |
fail=0
for f in pkgs/*/*.lua; do
# 1. Lua syntax check — load (= compile) without executing.
# `loadfile(name, 't')` rejects bytecode and parses text only.
if ! lua5.4 -e "assert(loadfile('$f', 't'))" >/dev/null 2>&1; then
echo "::error file=$f::lua syntax error"
fail=1
fi
# 2. xpkg V1 baseline: the file has to populate `package = { ... }`
# with at least `spec`, `name`, and an `xpm` table. Form A vs
# Form B (mcpp = "<path>" / mcpp = { ... }) is descriptor-author
# choice and not enforced here.
for needle in 'spec *=' 'name *=' 'xpm *='; do
if ! grep -q "$needle" "$f"; then
echo "::error file=$f::missing required field ($needle)"
fail=1
fi
done
# 3. Package version identifiers and dependency versions should be
# bare versions ("1.2.3"), not upstream tag names ("v1.2.3").
# Download URLs may still contain refs/tags/v* when upstream
# uses that tag spelling.
if grep -nE '\["v[0-9]+|\["[^"]+"\][[:space:]]*=[[:space:]]*"v[0-9]+' "$f"; then
echo "::error file=$f::version identifiers must not use a leading v"
fail=1
fi
# 4. Mirror table sanity: when a download `url` is written as a
# { GLOBAL=..., CN=... } table, both regions must be present and
# the CN entry must point at the gitcode mcpp-res mirror.
if ! lua5.4 tests/check_mirror_urls.lua "$f"; then
fail=1
fi
done
[ $fail -eq 0 ] && echo "All package files valid."
exit $fail
mirror-cn-reachable:
# Closed-loop guard for the CN mirror: every CN url referenced by a
# descriptor must be a live, downloadable gitcode release asset.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install lua
run: sudo apt-get install -y --no-install-recommends lua5.4
- name: Check CN mirror assets are reachable
run: |
fail=0
# collect unique CN urls across all descriptors
: > /tmp/cn.tsv
for f in pkgs/*/*.lua; do
lua5.4 tests/list_cn_urls.lua "$f" >> /tmp/cn.tsv || true
done
sort -u /tmp/cn.tsv -o /tmp/cn.tsv
total=$(grep -c . /tmp/cn.tsv || true)
echo "checking $total CN mirror url(s)"
while IFS=$'\t' read -r url sha; do
[ -z "$url" ] && continue
# follow redirects; gitcode release assets resolve to object storage
code=$(curl -fsSL -o /dev/null -w '%{http_code}' --retry 2 --max-time 60 "$url" || echo "000")
if [ "$code" != "200" ]; then
echo "::error::CN mirror unreachable ($code): $url"
fail=1
else
echo "ok: $url"
fi
done < /tmp/cn.tsv
[ $fail -eq 0 ] && echo "All CN mirror urls reachable."
exit $fail
# ── Decide what to smoke-test ─────────────────────────────────────────
# PR builds run ONLY the example projects whose package descriptor changed
# (tests/examples/<pkg>/). Anything that can't be narrowed that way — a
# changed pkg without an example yet, a scaffolding/CI change, or a
# push/nightly/manual run — falls back to the full legacy smoke regression.
detect:
runs-on: ubuntu-latest
outputs:
examples: ${{ steps.f.outputs.examples }}
full: ${{ steps.f.outputs.full }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install jq
run: sudo apt-get install -y --no-install-recommends jq
- id: f
run: |
full=false
examples='[]'
event="${{ github.event_name }}"
if [ "$event" != "pull_request" ]; then
# push to main / nightly schedule / manual dispatch → full regression
full=true
else
git fetch -q origin "${{ github.base_ref }}"
changed=$(git diff --name-only "origin/${{ github.base_ref }}...HEAD")
echo "changed files:"; echo "$changed" | sed 's/^/ /'
# scaffolding / CI change → full regression
if echo "$changed" | grep -qE '^(tests/run_example\.sh|tests/smoke_.*\.sh|tests/check_mirror_urls\.lua|tests/list_cn_urls\.lua|\.github/workflows/validate\.yml)$'; then
full=true
fi
sel=""
while IFS= read -r file; do
case "$file" in
pkgs/*/*.lua)
b=$(basename "$file" .lua); b=${b#compat.}
if [ -d "tests/examples/$b" ]; then
sel="$sel$b"$'\n'
else
# changed pkg with no example yet → cannot narrow, run full
full=true
fi
;;
esac
done <<< "$changed"
if [ -n "$sel" ]; then
examples=$(printf '%s' "$sel" | grep -v '^$' | sort -u | jq -R . | jq -sc .)
fi
fi
echo "full=$full" >> "$GITHUB_OUTPUT"
echo "examples=$examples" >> "$GITHUB_OUTPUT"
echo "=> full=$full examples=$examples"
# ── Fast path: per-changed-package example projects (Linux) ───────────
smoke-examples:
needs: detect
if: needs.detect.outputs.examples != '[]'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
pkg: ${{ fromJson(needs.detect.outputs.examples) }}
steps:
- uses: actions/checkout@v4
- name: Restore mcpp registry cache
uses: actions/cache@v4
with:
path: ~/.mcpp/registry
key: mcpp-registry-${{ runner.os }}-${{ env.MCPP_VERSION }}-${{ hashFiles('pkgs/**/*.lua', 'tests/**', '.github/workflows/validate.yml') }}
restore-keys: |
mcpp-registry-${{ runner.os }}-${{ env.MCPP_VERSION }}-
- name: Download mcpp
run: |
curl -L -fsS -o mcpp.tar.gz \
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz"
tar -xzf mcpp.tar.gz
root="$PWD/mcpp-${MCPP_VERSION}-linux-x86_64"
mkdir -p "$HOME/.mcpp/registry"
cp -a "$root/registry/." "$HOME/.mcpp/registry/"
echo "MCPP=$root/bin/mcpp" >> "$GITHUB_ENV"
echo "MCPP_VENDORED_XLINGS=$root/registry/bin/xlings" >> "$GITHUB_ENV"
echo "$root/bin" >> "$GITHUB_PATH"
- name: Run example "${{ matrix.pkg }}"
env:
MCPP_INDEX_MIRROR: GLOBAL
run: |
"$MCPP" --version
timeout 1800 bash tests/run_example.sh "${{ matrix.pkg }}"
# ── Full regression (legacy whole-suite smoke) ────────────────────────
smoke-full-linux:
needs: detect
if: needs.detect.outputs.full == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Restore mcpp registry cache
uses: actions/cache@v4
with:
path: ~/.mcpp/registry
key: mcpp-registry-${{ runner.os }}-${{ env.MCPP_VERSION }}-${{ hashFiles('pkgs/**/*.lua', 'tests/**', '.github/workflows/validate.yml') }}
restore-keys: |
mcpp-registry-${{ runner.os }}-${{ env.MCPP_VERSION }}-
- name: Download mcpp
run: |
curl -L -fsS -o mcpp.tar.gz \
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz"
tar -xzf mcpp.tar.gz
root="$PWD/mcpp-${MCPP_VERSION}-linux-x86_64"
mkdir -p "$HOME/.mcpp/registry"
cp -a "$root/registry/." "$HOME/.mcpp/registry/"
echo "MCPP=$root/bin/mcpp" >> "$GITHUB_ENV"
echo "MCPP_VENDORED_XLINGS=$root/registry/bin/xlings" >> "$GITHUB_ENV"
echo "$root/bin" >> "$GITHUB_PATH"
- name: Run compat smoke tests
env:
MCPP_INDEX_SMOKE_MCPP_HOME: ${{ runner.temp }}/mcpp-smoke-home
MCPP_INDEX_SMOKE_CACHE_DIR: ${{ runner.temp }}/mcpp-smoke-cache
run: |
mkdir -p "$MCPP_INDEX_SMOKE_MCPP_HOME"
"$MCPP" --version
timeout 1800 bash tests/smoke_compat_core.sh
timeout 1800 bash tests/smoke_compat_imgui.sh
timeout 1800 bash tests/smoke_compat_archive.sh
# GLFW/OpenGL window + imgui-module demos. These pull compat.glfw
# (abi:glibc). The imgui-module smoke pins llvm@20.1.7 (clang/libc++);
# on mcpp ≤0.0.67 that tripped the conflated `abi:` gate ("requires
# abi=glibc … is abi=libc++") because a clang+libc++ toolchain on
# *-linux-gnu was mislabelled. Fixed in mcpp 0.0.68 (dimensional ABI
# model: libc and cxxstdlib are independent axes), so these are back in
# the blocking set. The window run itself stays opt-in (needs a display).
timeout 1800 bash tests/smoke_compat_imgui_window.sh
timeout 1800 bash tests/smoke_imgui_module.sh
smoke-portable:
needs: detect
if: needs.detect.outputs.full == 'true'
name: smoke-${{ matrix.platform }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
- platform: macos
os: macos-15
archive: mcpp-0.0.73-macosx-arm64.tar.gz
root: mcpp-0.0.73-macosx-arm64
mcpp: bin/mcpp
xlings: registry/bin/xlings
- platform: windows
os: windows-latest
archive: mcpp-0.0.73-windows-x86_64.zip
root: mcpp-0.0.73-windows-x86_64
mcpp: bin/mcpp.exe
xlings: registry/bin/xlings.exe
steps:
- uses: actions/checkout@v4
- name: Restore mcpp registry cache
uses: actions/cache@v4
with:
path: ~/.mcpp/registry
key: mcpp-registry-${{ runner.os }}-${{ env.MCPP_VERSION }}-${{ hashFiles('pkgs/**/*.lua', 'tests/**', '.github/workflows/validate.yml') }}
restore-keys: |
mcpp-registry-${{ runner.os }}-${{ env.MCPP_VERSION }}-
- name: Download mcpp
shell: bash
env:
MCPP_ARCHIVE: ${{ matrix.archive }}
MCPP_ROOT: ${{ matrix.root }}
run: |
curl -L -fsS -o "$MCPP_ARCHIVE" \
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/${MCPP_ARCHIVE}"
case "$MCPP_ARCHIVE" in
*.zip)
powershell -NoProfile -Command "Expand-Archive -Force -Path '${MCPP_ARCHIVE}' -DestinationPath '.'"
;;
*)
tar -xzf "$MCPP_ARCHIVE"
;;
esac
root="$PWD/$MCPP_ROOT"
mkdir -p "$HOME/.mcpp/registry"
cp -a "$root/registry/." "$HOME/.mcpp/registry/"
if [[ "$RUNNER_OS" == "Windows" ]]; then
echo "MCPP=$(cygpath -m "$root/${{ matrix.mcpp }}")" >> "$GITHUB_ENV"
echo "MCPP_VENDORED_XLINGS=$(cygpath -m "$root/${{ matrix.xlings }}")" >> "$GITHUB_ENV"
echo "$(cygpath -m "$root/bin")" >> "$GITHUB_PATH"
else
echo "MCPP=$root/${{ matrix.mcpp }}" >> "$GITHUB_ENV"
echo "MCPP_VENDORED_XLINGS=$root/${{ matrix.xlings }}" >> "$GITHUB_ENV"
echo "$root/bin" >> "$GITHUB_PATH"
fi
- name: Run portable compat smoke tests
shell: bash
env:
MCPP_INDEX_MIRROR: GLOBAL
run: |
"$MCPP" --version
bash tests/smoke_compat_portable.sh