Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 109 additions & 30 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3129,19 +3129,42 @@ jobs:
MAVEN_GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
# Runs even when the deploy step failed: a Central publish-poll timeout reds the
# job *after* the bundle was uploaded (and typically published server-side), while
# the signed jars + .asc files already exist in target/ (signing happens at
# the signed jars and poms + .asc files already exist in target/ (signing happens at
# verify). Collecting on failure lets the github-snapshot job still attach them.
- name: Collect signed artifacts
if: ${{ !cancelled() }}
run: |
mkdir -p signed-snapshot-assets
cp llama/target/*.jar signed-snapshot-assets/ 2>/dev/null || true
cp llama/target/*.jar.asc signed-snapshot-assets/ 2>/dev/null || true
cp llama-langchain4j/target/*.jar signed-snapshot-assets/ 2>/dev/null || true
cp llama-langchain4j/target/*.jar.asc signed-snapshot-assets/ 2>/dev/null || true
cp llama-kotlin/target/*.jar signed-snapshot-assets/ 2>/dev/null || true
cp llama-kotlin/target/*.jar.asc signed-snapshot-assets/ 2>/dev/null || true
cp llama-android/build/aar/*.aar signed-snapshot-assets/ 2>/dev/null || true
# Every Maven artifact Central gets, with its .asc: the jars of every jar module and the
# pom of every module -- maven-gpg writes target/<artifactId>-<version>.pom next to its
# .pom.asc, also for the pom-only modules (`.` is llama-parent, llama-platform is the one
# consumers are told to depend on and used to be absent from the release entirely).
for m in . llama llama-langchain4j llama-kotlin llama-platform llama-atmosphere-agent; do
cp "$m"/target/*.jar signed-snapshot-assets/ 2>/dev/null || true
cp "$m"/target/*.jar.asc signed-snapshot-assets/ 2>/dev/null || true
cp "$m"/target/*.pom signed-snapshot-assets/ 2>/dev/null || true
cp "$m"/target/*.pom.asc signed-snapshot-assets/ 2>/dev/null || true
done
# The two AARs, as Central names them: Gradle signs the AAR next to itself
# (build/aar/*.aar.asc -- the signature was always there, it was never copied), each
# publication's pom as build/publications/<publication>/pom-default.xml(.asc), and the
# sources/javadoc jars the two publications share under build/distributions/.
for aar in llama-android/build/aar/*.aar; do
[ -e "$aar" ] || continue
base="$(basename "$aar" .aar)"
case "$base" in
llama-android-opencl-*) pub=llamaAndroidOpencl; v="${base#llama-android-opencl-}" ;;
*) pub=llamaAndroid; v="${base#llama-android-}" ;;
esac
cp "$aar" signed-snapshot-assets/ 2>/dev/null || true
cp "$aar.asc" signed-snapshot-assets/ 2>/dev/null || true
cp "llama-android/build/publications/$pub/pom-default.xml" "signed-snapshot-assets/$base.pom" 2>/dev/null || true
cp "llama-android/build/publications/$pub/pom-default.xml.asc" "signed-snapshot-assets/$base.pom.asc" 2>/dev/null || true
for c in sources javadoc; do
cp "llama-android/build/distributions/llama-android-$v-$c.jar" "signed-snapshot-assets/$base-$c.jar" 2>/dev/null || true
cp "llama-android/build/distributions/llama-android-$v-$c.jar.asc" "signed-snapshot-assets/$base-$c.jar.asc" 2>/dev/null || true
done
done
- uses: actions/upload-artifact@v7
if: ${{ !cancelled() }}
with:
Expand Down Expand Up @@ -3180,21 +3203,23 @@ jobs:
run: |
set -uo pipefail
dir="snapshot-assets"
jars=$(find "$dir" -maxdepth 1 -name '*.jar' | sort)
if [ -z "$jars" ]; then
echo "::error::no jars in $dir -- the collection step produced nothing"
# Every attachable artifact type, not only jars: with '*.jar' alone the AARs were attached
# unsigned for months and nothing counted them, so the job reported success.
artifacts=$(find "$dir" -maxdepth 1 \( -name '*.jar' -o -name '*.aar' -o -name '*.pom' \) | sort)
if [ -z "$artifacts" ]; then
echo "::error::no artifacts in $dir -- the collection step produced nothing"
echo "missing=-1" >> "$GITHUB_OUTPUT"
exit 0
fi
missing=0
for jar in $jars; do
if [ ! -e "$jar.asc" ]; then
echo "::error::unsigned: $(basename "$jar") has no detached .asc"
for artifact in $artifacts; do
if [ ! -e "$artifact.asc" ]; then
echo "::error::unsigned: $(basename "$artifact") has no detached .asc"
missing=$((missing + 1))
fi
done
echo "missing=$missing" >> "$GITHUB_OUTPUT"
[ "$missing" -eq 0 ] && echo "all $(echo "$jars" | wc -l) jar(s) signed"
[ "$missing" -eq 0 ] && echo "all $(echo "$artifacts" | wc -l) artifact(s) signed"
exit 0
- name: Update snapshot pre-release
env:
Expand All @@ -3209,6 +3234,35 @@ jobs:
gh release upload snapshot snapshot-assets/* \
--repo ${{ github.repository }} \
--clobber
- name: Remove the assets this run did not upload
# `snapshot` is a rolling "latest" pre-release, and `gh release upload --clobber` replaces
# same-named assets but never removes any other, so every asset of every past version stayed
# forever: 208 on java-llama.cpp (109 of them from 5.0.x, 43 in shapes that no longer exist),
# and SpotBugs plugin jars an old collect step attached in 2026-05 on three repositories. A
# non-current asset on this release is noise by definition. The keep-set is what this run
# uploaded -- the files in the asset directory -- never a version pattern, which would have to
# be re-taught at every classifier added or dropped (how the stale shapes arose). AFTER the
# upload on purpose: a failed upload must not leave the release emptier than it was. And only
# here: a versioned v* release is history, github-release never deletes anything. Every
# deletion is printed by name, so the job log is the audit trail.
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
keep="$(ls -1 snapshot-assets | sort)"
current="$(gh release view snapshot --repo ${{ github.repository }} --json assets --jq '.assets[].name' | sort)"
stale="$(comm -13 <(printf '%s\n' "$keep") <(printf '%s\n' "$current"))"
if [ -z "$stale" ]; then
echo "nothing to remove: the release holds exactly the $(printf '%s\n' "$keep" | wc -l) asset(s) of this upload"
exit 0
fi
echo "removing $(printf '%s\n' "$stale" | wc -l) asset(s) that are not part of this upload:"
while IFS= read -r name; do
[ -n "$name" ] || continue
echo " deleting $name"
gh release delete-asset snapshot "$name" --repo ${{ github.repository }} --yes
done <<< "$stale"
echo "kept the $(printf '%s\n' "$keep" | wc -l) asset(s) of this upload"
- name: Fail if anything was attached unsigned
# After the upload on purpose: the assets must exist even when the signature does not.
if: ${{ always() && steps.signatures.outputs.missing != '0' }}
Expand Down Expand Up @@ -3313,19 +3367,42 @@ jobs:
MAVEN_GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
# Runs even when the deploy step failed: a Central publish-poll timeout reds the
# job *after* the bundle was uploaded (and typically published server-side), while
# the signed jars + .asc files already exist in target/ (signing happens at
# the signed jars and poms + .asc files already exist in target/ (signing happens at
# verify). Collecting on failure lets the github-release-signed job still attach them.
- name: Collect signed artifacts
if: ${{ !cancelled() }}
run: |
mkdir -p signed-release-assets
cp llama/target/*.jar signed-release-assets/ 2>/dev/null || true
cp llama/target/*.jar.asc signed-release-assets/ 2>/dev/null || true
cp llama-langchain4j/target/*.jar signed-release-assets/ 2>/dev/null || true
cp llama-langchain4j/target/*.jar.asc signed-release-assets/ 2>/dev/null || true
cp llama-kotlin/target/*.jar signed-release-assets/ 2>/dev/null || true
cp llama-kotlin/target/*.jar.asc signed-release-assets/ 2>/dev/null || true
cp llama-android/build/aar/*.aar signed-release-assets/ 2>/dev/null || true
# Every Maven artifact Central gets, with its .asc: the jars of every jar module and the
# pom of every module -- maven-gpg writes target/<artifactId>-<version>.pom next to its
# .pom.asc, also for the pom-only modules (`.` is llama-parent, llama-platform is the one
# consumers are told to depend on and used to be absent from the release entirely).
for m in . llama llama-langchain4j llama-kotlin llama-platform llama-atmosphere-agent; do
cp "$m"/target/*.jar signed-release-assets/ 2>/dev/null || true
cp "$m"/target/*.jar.asc signed-release-assets/ 2>/dev/null || true
cp "$m"/target/*.pom signed-release-assets/ 2>/dev/null || true
cp "$m"/target/*.pom.asc signed-release-assets/ 2>/dev/null || true
done
# The two AARs, as Central names them: Gradle signs the AAR next to itself
# (build/aar/*.aar.asc -- the signature was always there, it was never copied), each
# publication's pom as build/publications/<publication>/pom-default.xml(.asc), and the
# sources/javadoc jars the two publications share under build/distributions/.
for aar in llama-android/build/aar/*.aar; do
[ -e "$aar" ] || continue
base="$(basename "$aar" .aar)"
case "$base" in
llama-android-opencl-*) pub=llamaAndroidOpencl; v="${base#llama-android-opencl-}" ;;
*) pub=llamaAndroid; v="${base#llama-android-}" ;;
esac
cp "$aar" signed-release-assets/ 2>/dev/null || true
cp "$aar.asc" signed-release-assets/ 2>/dev/null || true
cp "llama-android/build/publications/$pub/pom-default.xml" "signed-release-assets/$base.pom" 2>/dev/null || true
cp "llama-android/build/publications/$pub/pom-default.xml.asc" "signed-release-assets/$base.pom.asc" 2>/dev/null || true
for c in sources javadoc; do
cp "llama-android/build/distributions/llama-android-$v-$c.jar" "signed-release-assets/$base-$c.jar" 2>/dev/null || true
cp "llama-android/build/distributions/llama-android-$v-$c.jar.asc" "signed-release-assets/$base-$c.jar.asc" 2>/dev/null || true
done
done
- uses: actions/upload-artifact@v7
if: ${{ !cancelled() }}
with:
Expand Down Expand Up @@ -3364,21 +3441,23 @@ jobs:
run: |
set -uo pipefail
dir="release-assets"
jars=$(find "$dir" -maxdepth 1 -name '*.jar' | sort)
if [ -z "$jars" ]; then
echo "::error::no jars in $dir -- the collection step produced nothing"
# Every attachable artifact type, not only jars: with '*.jar' alone the AARs were attached
# unsigned for months and nothing counted them, so the job reported success.
artifacts=$(find "$dir" -maxdepth 1 \( -name '*.jar' -o -name '*.aar' -o -name '*.pom' \) | sort)
if [ -z "$artifacts" ]; then
echo "::error::no artifacts in $dir -- the collection step produced nothing"
echo "missing=-1" >> "$GITHUB_OUTPUT"
exit 0
fi
missing=0
for jar in $jars; do
if [ ! -e "$jar.asc" ]; then
echo "::error::unsigned: $(basename "$jar") has no detached .asc"
for artifact in $artifacts; do
if [ ! -e "$artifact.asc" ]; then
echo "::error::unsigned: $(basename "$artifact") has no detached .asc"
missing=$((missing + 1))
fi
done
echo "missing=$missing" >> "$GITHUB_OUTPUT"
[ "$missing" -eq 0 ] && echo "all $(echo "$jars" | wc -l) jar(s) signed"
[ "$missing" -eq 0 ] && echo "all $(echo "$artifacts" | wc -l) artifact(s) signed"
exit 0
- name: Upload release assets
uses: softprops/action-gh-release@v3
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,21 @@ from version 5.0.0 onward. Pre-fork releases (`1.x`–`4.2.0`) were authored by
changed meaning accordingly (see Added).

### Fixed
- **The GitHub `snapshot` pre-release and the versioned releases carry what Maven Central carries,
and the `snapshot` release no longer accumulates.** The collect steps copied `*.jar` / `*.jar.asc`
and the bare AARs, so every `.pom` with its `.pom.asc` was missing, `llama-platform` (a pom-only
module, the artifact consumers are told to depend on) was absent from the release entirely, the
AARs were attached **unsigned** although Gradle had written their `.asc` next to them, and the
agent's thin jar was never attached; the signature check globbed `*.jar` only, so the unsigned AARs
never turned the job red. Now every module's jars and poms (`llama-parent` and `llama-platform`
included), the AARs with their signatures, poms and sources/javadoc jars, and the agent's thin jar
are collected in both the snapshot and the release job, the check counts jars, AARs and poms, and
`github-snapshot` deletes every asset the run did not upload, after the upload and each printed by
name -- `gh release upload --clobber` never removed anything, so the release held 208 assets, 109 of
them from 5.0.x and 43 in shapes that no longer exist (`msvc-windows`,
`all-*-jar-with-dependencies`), plus three SpotBugs plugin jars an old collect step attached in
2026-05. Versioned releases are never pruned; the next snapshot run clears the backlog by itself
(`workspace/policies/fat-jar-release-assets.md`).
- **A Windows build on an AMX CPU (Sapphire, Emerald or Granite Rapids) crashed the JVM with
`STATUS_HEAP_CORRUPTION` when a model was unloaded.** ggml's AMX weight buffer -- used by the
`sapphirerapids` CPU module for Q4_0/Q4_1/Q8_0/Q4_K/Q5_K/Q6_K/IQ4_XS weights -- is allocated with
Expand Down
17 changes: 14 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1039,9 +1039,20 @@ unlaunched.

`publish-snapshot` / `publish-release` `need` all three (a matrix job is done when every row is;
fail-loud gating). `github-snapshot` / `github-release-signed` then attach the Maven artifacts with
the `.asc` maven-gpg wrote at deploy -- the classes jar, every natives jar, the poms, sources,
javadoc, the AARs -- and nothing is signed or assembled in those jobs any more (no `sign-fatjars.sh`,
no `environment:`; `verify-signing-key` still proves the key, and the publish jobs sign with it).
the `.asc` maven-gpg wrote at deploy -- the classes jar, every natives jar, every module's pom
(`llama-parent` and `llama-platform` included: maven-gpg writes `target/<artifactId>-<version>.pom`
next to its `.pom.asc`, also for a pom-only module), sources, javadoc, the agent's thin jar, and the
two AARs with the `.aar.asc` Gradle writes next to them, their poms
(`build/publications/<publication>/pom-default.xml`) and their sources/javadoc jars
(`build/distributions/`) -- and nothing is signed or assembled in those jobs any more (no
`sign-fatjars.sh`, no `environment:`; `verify-signing-key` still proves the key, and the publish jobs
sign with it). Until 2026-10-12 the collect steps copied jars and bare AARs only: every pom was
missing, `llama-platform` was absent entirely, the AARs went out unsigned and the `*.jar`-only
signature check never noticed. The check counts jars, AARs and poms now, and `github-snapshot` ends by
deleting every asset of the `snapshot` pre-release the run did not upload, each printed by name
(`gh release upload --clobber` never removed anything: 208 assets, 109 of them from 5.0.x); a versioned
release is never pruned (`workspace/policies/fat-jar-release-assets.md`, "The `snapshot` pre-release
holds exactly the current upload").

The common part of the three smoke scripts is `.github/smoke-lib.sh` (`smoke_classpath`,
`smoke_set_modules`, `smoke_assert_loader_line`); the PowerShell script repeats it, since the Windows
Expand Down
Loading