Phase 1 foundation: kherud fork + repo scaffolding #3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |