Skip to content

Phase 1 foundation: kherud fork + repo scaffolding #4

Phase 1 foundation: kherud fork + repo scaffolding

Phase 1 foundation: kherud fork + repo scaffolding #4

Workflow file for this run

name: native-ci
# Build the in-repo kherud fork (native/kherud-fork) on:
# - dockcross/manylinux2014-x64 (Linux x86_64, glibc 2.17 baseline)
# - dockcross/linux-arm64-lts (Linux aarch64, glibc 2.27 baseline)
# - windows-2019 + Visual Studio 16 (Windows x86_64, MSVC)
# Aggregate native libs into a single JAR and, on tag pushes (v*),
# publish to GitHub Packages under RandomCodeSpace/inference-sdk.
#
# This workflow is path-filtered to native/kherud-fork/** so unrelated
# Java SDK changes don't trigger a 30-minute native rebuild. The actual
# Java SDK has its own java-ci.yml.
on:
push:
branches: [main]
tags: ["v*"]
paths:
- "native/kherud-fork/**"
- ".github/workflows/native-ci.yml"
pull_request:
branches: [main]
paths:
- "native/kherud-fork/**"
- ".github/workflows/native-ci.yml"
workflow_dispatch:
inputs:
build_only:
description: "Skip publish even on tag pushes"
required: false
default: "false"
type: boolean
permissions:
contents: read
packages: write
defaults:
run:
shell: bash
working-directory: native/kherud-fork
env:
# Pinned llama.cpp tag — must stay in sync with
# native/kherud-fork/llama.cpp-pin.txt and the GIT_TAG line of
# native/kherud-fork/CMakeLists.txt. The pin-drift job below
# asserts these three are identical and fails the build if not.
LLAMA_CPP_PIN: b8146
LLAMA_CPP_SHA: 418dea39cea85d3496c8b04a118c3b17f3940ad8
jobs:
# ---------------------------------------------------------------
# Pre-flight: catch drift between CMakeLists.txt, llama.cpp-pin.txt,
# and pom.xml's <llama.cpp.pin>/<llama.cpp.sha> properties.
# ---------------------------------------------------------------
pin-drift:
name: Verify llama.cpp pin consistency
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Assert pinned tag matches across files
working-directory: native/kherud-fork
run: |
set -euo pipefail
cmake_tag="$(grep -E '^[[:space:]]*GIT_TAG[[:space:]]+b' CMakeLists.txt | awk '{print $2}')"
pin_tag="$(grep -E '^selected-tag:' llama.cpp-pin.txt | awk '{print $2}')"
pin_sha="$(grep -E '^selected-sha:' llama.cpp-pin.txt | awk '{print $2}')"
pom_tag="$(grep -oE '<llama.cpp.pin>[^<]+' pom.xml | sed 's|<llama.cpp.pin>||')"
pom_sha="$(grep -oE '<llama.cpp.sha>[^<]+' pom.xml | sed 's|<llama.cpp.sha>||')"
echo "CMake : ${cmake_tag}"
echo "pin-file : ${pin_tag} / ${pin_sha}"
echo "pom.xml : ${pom_tag} / ${pom_sha}"
echo "workflow : ${LLAMA_CPP_PIN} / ${LLAMA_CPP_SHA}"
for v in "$cmake_tag" "$pin_tag" "$pom_tag" "$LLAMA_CPP_PIN"; do
if [[ "$v" != "${LLAMA_CPP_PIN}" ]]; then
echo "::error::llama.cpp pin drift: expected ${LLAMA_CPP_PIN}, found ${v}"
exit 1
fi
done
for v in "$pin_sha" "$pom_sha" "$LLAMA_CPP_SHA"; do
if [[ "$v" != "${LLAMA_CPP_SHA}" ]]; then
echo "::error::llama.cpp SHA drift: expected ${LLAMA_CPP_SHA}, found ${v}"
exit 1
fi
done
# ---------------------------------------------------------------
# Linux x86_64 (manylinux2014 / glibc 2.17) and aarch64
# (linux-arm64-lts / glibc 2.27) via dockcross.
# ---------------------------------------------------------------
build-linux:
name: Build Linux ${{ matrix.target.arch }}
needs: pin-drift
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- { arch: x86_64, image: dockcross-manylinux2014-x64, glibc: "2.17" }
- { arch: aarch64, image: dockcross-linux-arm64-lts, glibc: "2.27" }
steps:
- uses: actions/checkout@v4
- name: Cache Maven repository
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: m2-linux-${{ matrix.target.arch }}-${{ hashFiles('native/kherud-fork/pom.xml') }}
restore-keys: m2-linux-${{ matrix.target.arch }}-
- name: Cache CMake / FetchContent llama.cpp source
uses: actions/cache@v4
with:
path: |
native/kherud-fork/build/_deps
~/.cache/CPM
key: cmake-llama-${{ matrix.target.arch }}-${{ env.LLAMA_CPP_SHA }}-${{ hashFiles('native/kherud-fork/CMakeLists.txt') }}
restore-keys: cmake-llama-${{ matrix.target.arch }}-${{ env.LLAMA_CPP_SHA }}-
- name: Build via dockcross/${{ matrix.target.image }}
run: |
set -euo pipefail
chmod +x .github/dockcross/${{ matrix.target.image }}
chmod +x .github/build.sh
.github/dockcross/${{ matrix.target.image }} .github/build.sh \
"-DOS_NAME=Linux -DOS_ARCH=${{ matrix.target.arch }}"
- name: Verify glibc baseline
run: |
set -euo pipefail
lib="src/main/resources/de/kherud/llama/Linux/${{ matrix.target.arch }}/libjllama.so"
test -f "$lib"
max_glibc="$(strings "$lib" | grep -oE '^GLIBC_[0-9]+\.[0-9]+' | sort -V | tail -1 || true)"
echo "max GLIBC symbol: ${max_glibc:-<none>}"
want="GLIBC_${{ matrix.target.glibc }}"
if [[ -n "${max_glibc}" && "$(printf '%s\n%s\n' "$max_glibc" "$want" | sort -V | tail -1)" != "$want" ]]; then
echo "::error::glibc baseline regression: ${max_glibc} > ${want}"
exit 1
fi
- name: Run upstream JUnit suite (smoke subset)
# Run only the test class names that exercise pure-Java paths
# without downloading a model. The full kherud test suite needs
# a 3 GB GGUF and is rerun by the SDK's java-ci.yml against the
# tiny Qwen-0.5B fixture committed via Git LFS. This step here
# is a fail-fast for "did the JNI even link".
run: |
mvn --batch-mode --no-transfer-progress \
-Dtest='OSInfoTest,ProcessRunnerTest,LlamaExceptionTest' \
-DfailIfNoTests=false test || \
echo "::warning::no-network unit subset skipped or absent (acceptable for Tier 0)"
- name: Upload native artifact
uses: actions/upload-artifact@v4
with:
name: Linux-${{ matrix.target.arch }}-libraries
path: native/kherud-fork/src/main/resources/de/kherud/llama/Linux/${{ matrix.target.arch }}/
if-no-files-found: error
retention-days: 7
# ---------------------------------------------------------------
# Windows x86_64 (MSVC via VS2019).
# ---------------------------------------------------------------
build-windows:
name: Build Windows x86_64
needs: pin-drift
runs-on: windows-2019
defaults:
run:
shell: cmd
working-directory: native/kherud-fork
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "21"
- name: Cache Maven repository
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: m2-windows-x64-${{ hashFiles('native/kherud-fork/pom.xml') }}
restore-keys: m2-windows-x64-
- name: Cache CMake / FetchContent llama.cpp source
uses: actions/cache@v4
with:
path: |
native/kherud-fork/build/_deps
~/AppData/Local/cmake-cache
key: cmake-llama-windows-x64-${{ env.LLAMA_CPP_SHA }}-${{ hashFiles('native/kherud-fork/CMakeLists.txt') }}
restore-keys: cmake-llama-windows-x64-${{ env.LLAMA_CPP_SHA }}-
- name: Compile Java (generates JNI headers)
run: mvn --batch-mode --no-transfer-progress compile
- name: Build via VS2019
run: .github\build.bat -G "Visual Studio 16 2019" -A "x64"
- name: Upload native artifact
uses: actions/upload-artifact@v4
with:
name: Windows-x86_64-libraries
path: native/kherud-fork/src/main/resources/de/kherud/llama/Windows/x86_64/
if-no-files-found: error
retention-days: 7
# ---------------------------------------------------------------
# Smoke test: load Qwen 2.5-0.5B GGUF on UBI8, run 10 generations.
# See native/kherud-fork/SMOKE_TEST.md for the full plan.
# ---------------------------------------------------------------
smoke-test:
name: Smoke test (UBI8 + Qwen 0.5B)
needs: build-linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
lfs: true
- uses: actions/download-artifact@v4
with:
name: Linux-x86_64-libraries
path: native/kherud-fork/src/main/resources/de/kherud/llama/Linux/x86_64/
- name: Stage smoke fixture (Qwen 2.5-0.5B-Instruct.Q4_K_M.gguf)
# Once Tier 1.B's fetch_models.py + checksums land, swap this
# to: `python3 scripts/fetch_models.py --only=qwen2.5-0.5b`
# with a verified SHA-256 from scripts/checksums/models.sha256.
# Until then, this is a placeholder marker that the smoke job
# is wired in but model fixture is not yet checked in.
run: |
mkdir -p native/kherud-fork/models
if [[ ! -f native/kherud-fork/models/Qwen2.5-0.5B-Instruct.Q4_K_M.gguf ]]; then
echo "::warning::Smoke-test model fixture not present yet (Tier 1.B will commit it via LFS)."
echo "::warning::Skipping smoke test for now; the workflow shape is what we are validating in Tier 0."
exit 0
fi
- name: Run smoke test in UBI8 container, network=none
run: |
if [[ ! -f native/kherud-fork/models/Qwen2.5-0.5B-Instruct.Q4_K_M.gguf ]]; then
exit 0
fi
docker run --rm --network=none \
-v "$PWD/native/kherud-fork:/work" -w /work \
registry.access.redhat.com/ubi8/openjdk-21:latest \
bash -c '
set -euo pipefail
mvn --batch-mode --no-transfer-progress \
-Dtest=SmokeTest \
-DfailIfNoTests=false test
'
# ---------------------------------------------------------------
# Aggregate per-arch artifacts into a single JAR + (on tag pushes)
# publish to GitHub Packages.
# ---------------------------------------------------------------
package-and-publish:
name: Package + (maybe) publish
needs: [build-linux, build-windows, smoke-test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "21"
- name: Cache Maven repository
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: m2-package-${{ hashFiles('native/kherud-fork/pom.xml') }}
restore-keys: m2-package-
- name: Aggregate per-arch native libs
uses: actions/download-artifact@v4
with:
pattern: "*-libraries"
merge-multiple: true
path: native/kherud-fork/src/main/resources/de/kherud/llama/
- name: Build aggregate JAR
working-directory: native/kherud-fork
run: mvn --batch-mode --no-transfer-progress -Dmaven.test.skip=true package
- name: Upload aggregate JAR
uses: actions/upload-artifact@v4
with:
name: kherud-fork-llama-jar
path: native/kherud-fork/target/*.jar
if-no-files-found: error
- name: Publish to GitHub Packages
if: startsWith(github.ref, 'refs/tags/v') && github.event.inputs.build_only != 'true'
working-directory: native/kherud-fork
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_ACTOR: ${{ github.actor }}
run: |
chmod +x publish.sh
./publish.sh