feat!: modularize stemmer models and release infrastructure

Move bundled stemmer dictionaries from the core artifact into independently
versioned model modules. Add model discovery and explicit model-loading APIs,
a standard model aggregate, a model BOM, and dedicated model and catalog
release workflows.

Add full PoliMorf integration, model provenance and licensing validation,
streaming model-input verification, strict dependency verification, consumer
resolution tests, Configuration Cache compatibility, and expanded JMH,
quality, documentation, and release checks.

Upgrade the CycloneDX and JMH Gradle plugins and remove Gradle 10 and Java
compiler deprecations.

BREAKING CHANGE: The core Radixor artifact no longer contains bundled stemmer
dictionaries. Applications must add the required model artifacts, the standard
model aggregate, or model dependencies managed through the Radixor model BOM.
This commit is contained in:
2026-07-22 23:33:28 +02:00
parent 9c5b9e331b
commit e7800b29c9
250 changed files with 7297 additions and 905 deletions

View File

@@ -10,6 +10,8 @@ on:
paths:
- 'src/main/**'
- 'src/jmh/**'
- 'models/**'
- 'build-logic/**'
- 'build.gradle'
- 'gradle.properties'
- 'gradle.lockfile'

View File

@@ -51,7 +51,7 @@ jobs:
test -f gradle/verification-metadata.xml
- name: Execute build, tests, PMD, coverage, Javadoc, distribution packaging, and SBOM generation
run: ./gradlew --no-daemon clean ciRelease distZip pmdMain javadoc jacocoCiReleaseReport cyclonedxBom
run: ./gradlew --no-daemon clean ciRelease distZip pmdMain javadoc jacocoCiReleaseReport :cyclonedxDirectBom
- name: Upload SBOM
if: always()
@@ -156,11 +156,14 @@ jobs:
test -f gradle.properties
test -f gradle/verification-metadata.xml
- name: Validate exact core release tag
run: ./tools/parse-model-release-tag.sh "${GITHUB_REF_NAME}" .
- name: Build release inputs, signed Maven bundle, and SBOM
env:
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
run: ./gradlew --no-daemon clean ciRelease distZip pmdMain javadoc jacocoCiReleaseReport cyclonedxBom centralBundle
run: ./gradlew --no-daemon clean ciRelease distZip pmdMain javadoc jacocoCiReleaseReport :cyclonedxDirectBom centralBundle
- name: Generate release changelog
shell: bash
@@ -177,24 +180,7 @@ jobs:
shell: bash
env:
CENTRAL_BEARER_TOKEN: ${{ secrets.CENTRAL_BEARER_TOKEN }}
run: |
set -euo pipefail
echo "::add-mask::$CENTRAL_BEARER_TOKEN"
BUNDLE="$(ls build/central-bundle/*.zip)"
HEADER_FILE="$(mktemp)"
trap 'rm -f "$HEADER_FILE"' EXIT
printf 'Authorization: Bearer %s\n' "$CENTRAL_BEARER_TOKEN" > "$HEADER_FILE"
curl \
--fail \
--silent \
--show-error \
--request POST \
--header @"$HEADER_FILE" \
--form "bundle=@${BUNDLE}" \
--form "name=org.egothor:radixor:${GITHUB_REF_NAME#release@}" \
"https://central.sonatype.com/api/v1/publisher/upload?publishingType=AUTOMATIC"
run: ./tools/publish-central-bundle.sh "$(ls build/central-bundle/*.zip)" "org.egothor:radixor:${GITHUB_REF_NAME#release@}"
- name: Publish GitHub release assets
uses: softprops/action-gh-release@v2

37
.github/workflows/catalog-release.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Model Catalog Release
on:
push:
tags:
- 'models-catalog@*'
permissions:
contents: read
concurrency:
group: model-catalog-${{ github.ref_name }}
cancel-in-progress: false
jobs:
catalog:
runs-on: ubuntu-latest
environment: maven-central
steps:
- uses: actions/checkout@v4
- uses: gradle/actions/wrapper-validation@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- uses: gradle/actions/setup-gradle@v4
- name: Validate catalog tag
run: ./tools/parse-model-release-tag.sh "${GITHUB_REF_NAME}" .
- name: Build only signed catalog metadata
env:
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
run: ./gradlew --no-daemon verifyModelCatalogReleaseCandidate
- name: Publish only catalog metadata
env:
CENTRAL_BEARER_TOKEN: ${{ secrets.CENTRAL_BEARER_TOKEN }}
run: ./tools/publish-central-bundle.sh "build/model-catalog-release-candidate/radixor-models-catalog-${GITHUB_REF_NAME#models-catalog@}-central-bundle.zip" "org.egothor:radixor-models-catalog:${GITHUB_REF_NAME#models-catalog@}"

147
.github/workflows/model-release.yml vendored Normal file
View File

@@ -0,0 +1,147 @@
name: Model Release
on:
push:
tags:
- 'model/*@*'
workflow_dispatch:
inputs:
tag:
description: Model tag to validate without publishing
required: true
type: string
permissions:
contents: read
concurrency:
group: model-release-${{ github.event_name == 'push' && github.ref_name || inputs.tag }}
cancel-in-progress: false
jobs:
validate:
name: Validate selected model
runs-on: ubuntu-latest
outputs:
model_id: ${{ steps.release.outputs.MODEL_ID }}
model_version: ${{ steps.release.outputs.MODEL_VERSION }}
gradle_project: ${{ steps.release.outputs.GRADLE_PROJECT }}
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Validate Gradle wrapper
uses: gradle/actions/wrapper-validation@v4
- name: Set up Temurin JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- name: Set up Gradle caching and instrumentation
uses: gradle/actions/setup-gradle@v4
- name: Verify reproducibility inputs
shell: bash
run: |
set -euo pipefail
test -f gradle.lockfile
test -f gradle.properties
test -f gradle/verification-metadata.xml
- name: Validate and select exactly one model
id: release
shell: bash
env:
REQUESTED_TAG: ${{ inputs.tag }}
run: |
set -euo pipefail
if [[ "${GITHUB_EVENT_NAME}" == "push" ]]; then
tag="${GITHUB_REF_NAME}"
else
tag="${REQUESTED_TAG}"
fi
./tools/parse-model-release-tag.sh "${tag}" . >> "${GITHUB_OUTPUT}"
git merge-base --is-ancestor "${GITHUB_SHA}" origin/main
- name: Validate one model
shell: bash
run: |
set -euo pipefail
project="${{ steps.release.outputs.GRADLE_PROJECT }}"
version="${{ steps.release.outputs.MODEL_VERSION }}"
./gradlew --no-daemon "${project}:clean"
./gradlew --no-daemon "${project}:check"
./gradlew --no-daemon \
"${project}:validateModelRelease" \
-PmodelReleaseVersion="${version}"
publish:
name: Publish selected model
if: github.event_name == 'push'
needs: validate
runs-on: ubuntu-latest
environment: maven-central
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Validate Gradle wrapper
uses: gradle/actions/wrapper-validation@v4
- name: Set up Temurin JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- name: Set up Gradle caching and instrumentation
uses: gradle/actions/setup-gradle@v4
- name: Verify reproducibility inputs
shell: bash
run: |
set -euo pipefail
test -f gradle.lockfile
test -f gradle.properties
test -f gradle/verification-metadata.xml
- name: Build signed model release candidate
shell: bash
env:
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
run: |
set -euo pipefail
project="${{ needs.validate.outputs.gradle_project }}"
version="${{ needs.validate.outputs.model_version }}"
./gradlew --no-daemon \
"${project}:packageModelReleaseCandidate" \
-PmodelReleaseVersion="${version}"
- name: Publish one model
shell: bash
env:
CENTRAL_BEARER_TOKEN: ${{ secrets.CENTRAL_BEARER_TOKEN }}
run: |
set -euo pipefail
model_id="${{ needs.validate.outputs.model_id }}"
version="${{ needs.validate.outputs.model_version }}"
./tools/publish-central-bundle.sh \
"models/${model_id}/build/model-release-candidate/central-bundle.zip" \
"org.egothor:radixor-model-${model_id}:${version}"

View File

@@ -10,6 +10,8 @@ on:
- 'src/main/**'
- 'src/test/**'
- 'src/jmh/**'
- 'models/**'
- 'build-logic/**'
- 'build.gradle'
- 'gradle.properties'
- 'gradle.lockfile'
@@ -70,7 +72,7 @@ jobs:
test -f gradle/verification-metadata.xml
- name: Build reports for publication
run: ./gradlew --no-daemon clean ciRelease pmdMain javadoc jacocoCiReleaseReport pitest jmh -Pjmh.includes='.*EnglishStemmerComparisonBenchmark.*' cyclonedxBom
run: ./gradlew --no-daemon clean ciRelease pmdMain javadoc jacocoCiReleaseReport pitest jmh -Pjmh.includes='.*EnglishStemmerComparisonBenchmark.*' :cyclonedxDirectBom
- name: Prepare gh-pages worktree
shell: bash
@@ -88,6 +90,9 @@ jobs:
cd ..
fi
- name: Prepare staged MkDocs source
run: ./gradlew --no-daemon prepareMkDocsSource verifyModelCatalogDocumentation
- name: Stage published reports
shell: bash
run: |
@@ -246,7 +251,7 @@ jobs:
cp "${RUN_DIR}/index.html" "${LATEST_DIR}/index.html"
cat > docs/reports.md <<EOF
cat > build/mkdocs-source/reports.md <<EOF
# CI Reports
Radixor publishes durable CI artifacts to GitHub Pages on every qualifying run of \`.github/workflows/pages.yml\`.
@@ -314,19 +319,18 @@ jobs:
| while IFS=$'\t' read -r _ts build published; do
echo "| ${build} | ${published} | [Open](../builds/${build}/) |"
done
} > docs/builds.md
} > build/mkdocs-source/builds.md
- name: Build documentation site (MkDocs Material)
shell: bash
run: |
set -euo pipefail
mkdocs build --strict --site-dir .mkdocs-site
rsync -a --delete --exclude '.git' --exclude '.git/' --exclude 'builds/' .mkdocs-site/ .gh-pages/
mkdocs build --strict --config-file build/mkdocs/mkdocs.yml
rsync -a --delete --exclude '.git' --exclude '.git/' --exclude 'builds/' build/mkdocs-site/ .gh-pages/
mkdir -p .gh-pages/builds
cp .mkdocs-site/builds/index.html .gh-pages/builds/index.html
cp build/mkdocs-site/builds/index.html .gh-pages/builds/index.html
cat > .gh-pages/.nojekyll <<EOF
EOF
rm -rf .mkdocs-site
- name: Commit and push gh-pages
shell: bash