Skip to content

Commit ccae248

Browse files
committed
feat: CLI distribution — install script, Docker image, CI tests, remove musl from Python/Node
- Remove musllinux targets from Python wheel builds (publish + CI) - Remove musl targets from Node.js NAPI builds - Replace cross-compiled musl CLI with Docker-based Alpine builds - Add cli-musl-binaries job using Dockerfile.musl-build for fully static binaries - Add docker/Dockerfile.cli for minimal CLI Docker image - Add scripts/install.sh curl-pipe-bash installer - Add CLI variant to publish-docker.yaml (ghcr.io/kreuzberg-dev/kreuzberg-cli) - Add test-docker-cli job to ci-docker.yaml with comprehensive tests - Add scripts/test_docker_cli.sh with 13 CLI Docker tests - Update docs with install script and CLI Docker instructions - Delete scripts/publish/cli/configure-musl-linker.sh (no longer needed)
1 parent f200ac6 commit ccae248

File tree

18 files changed

+1273
-359
lines changed

18 files changed

+1273
-359
lines changed

.github/workflows/ci-docker.yaml

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ on:
1212
- 'crates/kreuzberg/**'
1313
- 'crates/kreuzberg-cli/**'
1414
- 'crates/kreuzberg-tesseract/**'
15+
- 'crates/kreuzberg-pdfium-render/**'
1516
- 'docker/**'
1617
- '.dockerignore'
1718
- 'Cargo.toml'
1819
- 'Cargo.lock'
1920
- '.cargo/config.toml'
2021
- 'scripts/ci/docker/**'
22+
- 'scripts/test_docker*.sh'
2123
pull_request:
2224
branches: [main]
2325
paths:
@@ -26,12 +28,14 @@ on:
2628
- 'crates/kreuzberg/**'
2729
- 'crates/kreuzberg-cli/**'
2830
- 'crates/kreuzberg-tesseract/**'
31+
- 'crates/kreuzberg-pdfium-render/**'
2932
- 'docker/**'
3033
- '.dockerignore'
3134
- 'Cargo.toml'
3235
- 'Cargo.lock'
3336
- '.cargo/config.toml'
3437
- 'scripts/ci/docker/**'
38+
- 'scripts/test_docker*.sh'
3539
workflow_dispatch:
3640
inputs:
3741
skip_tests:
@@ -161,3 +165,103 @@ jobs:
161165
if: success()
162166
shell: bash
163167
run: scripts/ci/docker/summary.sh "${{ matrix.variant }}" /tmp/kreuzberg-docker-test-results.json
168+
169+
test-docker-cli:
170+
name: Build and Test Docker CLI Image
171+
if: ${{ github.actor != 'dependabot[bot]' }}
172+
runs-on: ubuntu-latest
173+
timeout-minutes: 180
174+
permissions:
175+
contents: read
176+
177+
steps:
178+
- name: Checkout repository
179+
uses: actions/checkout@v4
180+
181+
- name: Free up disk space
182+
shell: bash
183+
run: scripts/ci/docker/free-disk-space.sh
184+
185+
- name: Set up Docker Buildx
186+
uses: docker/setup-buildx-action@v3
187+
188+
- name: Build Docker CLI image
189+
uses: docker/build-push-action@v6
190+
with:
191+
context: .
192+
file: docker/Dockerfile.cli
193+
push: false
194+
load: true
195+
tags: kreuzberg:cli
196+
cache-from: type=gha
197+
cache-to: type=gha,mode=max,scope=ci-docker-cli
198+
199+
- name: Test Docker image size
200+
shell: bash
201+
run: |
202+
size_mb=$(docker inspect kreuzberg:cli --format='{{.Size}}' | awk '{print int($1/1024/1024)}')
203+
echo "CLI image size: ${size_mb}MB"
204+
if [ "$size_mb" -gt 200 ]; then
205+
echo "::warning::CLI image is larger than 200MB (${size_mb}MB). Expected a minimal static binary image."
206+
fi
207+
208+
- name: Run CLI feature tests
209+
if: ${{ !inputs.skip_tests }}
210+
run: scripts/ci/docker/run-cli-tests.sh
211+
212+
- name: Save Docker image as artifact
213+
if: success()
214+
shell: bash
215+
run: |
216+
mkdir -p /tmp
217+
docker save kreuzberg:cli | gzip > /tmp/kreuzberg-cli.tar.gz
218+
ls -lh /tmp/kreuzberg-cli.tar.gz
219+
220+
- name: Upload Docker image artifact
221+
if: success()
222+
uses: actions/upload-artifact@v4
223+
with:
224+
name: docker-image-cli
225+
path: /tmp/kreuzberg-cli.tar.gz
226+
retention-days: 7
227+
compression-level: 0
228+
229+
- name: Upload test results
230+
if: always() && !inputs.skip_tests && hashFiles('/tmp/kreuzberg-docker-cli-test-results.json') != ''
231+
uses: actions/upload-artifact@v4
232+
with:
233+
name: docker-test-results-cli
234+
path: /tmp/kreuzberg-docker-cli-test-results.json
235+
retention-days: 7
236+
237+
- name: Collect Docker logs on failure
238+
if: failure()
239+
shell: bash
240+
run: scripts/ci/docker/collect-logs.sh /tmp/docker-logs
241+
242+
- name: Upload Docker logs
243+
if: failure()
244+
uses: actions/upload-artifact@v4
245+
with:
246+
name: docker-logs-cli
247+
path: /tmp/docker-logs/
248+
retention-days: 7
249+
250+
- name: Clean up Docker resources
251+
if: always()
252+
shell: bash
253+
run: |
254+
docker ps -aq --filter "name=kreuzberg-cli-test" | xargs -r docker rm -f || true
255+
docker rmi kreuzberg:cli || true
256+
docker system prune -af --volumes || true
257+
258+
- name: Summary
259+
if: success()
260+
shell: bash
261+
run: |
262+
echo "Docker CLI image built and tested successfully!"
263+
echo "Image: kreuzberg:cli"
264+
if [ -f /tmp/kreuzberg-docker-cli-test-results.json ]; then
265+
echo "Test Results:"
266+
jq . < /tmp/kreuzberg-docker-cli-test-results.json || cat /tmp/kreuzberg-docker-cli-test-results.json
267+
fi

.github/workflows/ci-python.yaml

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -208,66 +208,6 @@ jobs:
208208
shell: bash
209209
run: scripts/ci/python/smoke-test-wheel.sh
210210

211-
build-musllinux-python:
212-
name: Python musllinux Build (${{ matrix.label }})
213-
if: ${{ github.actor != 'dependabot[bot]' }}
214-
timeout-minutes: 180
215-
strategy:
216-
fail-fast: true
217-
matrix:
218-
include:
219-
- os: ubuntu-latest
220-
label: linux-x86_64-musllinux
221-
rust_target: x86_64-unknown-linux-musl
222-
manylinux: musllinux_1_2
223-
- os: ubuntu-24.04-arm
224-
label: linux-aarch64-musllinux
225-
rust_target: aarch64-unknown-linux-musl
226-
manylinux: musllinux_1_2
227-
runs-on: ${{ matrix.os }}
228-
steps:
229-
- uses: actions/checkout@v4
230-
231-
- name: Free disk space before setup
232-
if: matrix.os == 'ubuntu-latest'
233-
uses: ./.github/actions/free-disk-space-linux
234-
with:
235-
show-initial: "true"
236-
show-final: "true"
237-
238-
- name: Build musllinux wheels
239-
uses: PyO3/maturin-action@v1
240-
with:
241-
command: build
242-
args: --release -i python3.10 --out ../../target/wheels
243-
target: ${{ matrix.rust_target }}
244-
manylinux: ${{ matrix.manylinux }}
245-
working-directory: packages/python
246-
sccache: false
247-
before-script-linux: |
248-
set -euo pipefail
249-
rustup component add rust-src || true
250-
if command -v apk &>/dev/null; then
251-
apk add --no-cache openssl-dev pkgconf clang clang-dev libc++-dev musl-dev cmake make build-base
252-
elif command -v apt-get &>/dev/null; then
253-
apt-get update && apt-get install -y libssl-dev pkg-config clang cmake make musl-tools
254-
fi
255-
echo "=== Building CLI Binary (musllinux) ==="
256-
cargo build --release --package kreuzberg-cli --features all
257-
mkdir -p kreuzberg
258-
cp ../../target/release/kreuzberg kreuzberg/kreuzberg-cli
259-
260-
- name: List built wheels
261-
shell: bash
262-
run: ls -lh target/wheels
263-
264-
- name: Upload wheels
265-
uses: actions/upload-artifact@v4
266-
with:
267-
name: wheels-${{ matrix.label }}
268-
path: target/wheels/*.whl
269-
retention-days: 7
270-
271211
build-python-sdist:
272212
name: Python Sdist
273213
if: ${{ github.actor != 'dependabot[bot]' }}

.github/workflows/publish-docker.yaml

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ jobs:
121121
outputs:
122122
core_exists: ${{ steps.core.outputs.exists }}
123123
full_exists: ${{ steps.full.outputs.exists }}
124+
cli_exists: ${{ steps.cli.outputs.exists }}
124125
steps:
125126
- name: Checkout code
126127
uses: actions/checkout@v4
@@ -148,6 +149,13 @@ jobs:
148149
SUMMARY_LABEL: full
149150
run: scripts/publish/check-docker-tag.sh
150151

152+
- name: Check CLI image tag
153+
id: cli
154+
env:
155+
DOCKER_TAG: ghcr.io/kreuzberg-dev/kreuzberg-cli:${{ needs.prepare.outputs.version }}
156+
SUMMARY_LABEL: cli
157+
run: scripts/publish/check-docker-tag.sh
158+
151159
publish-docker:
152160
name: Publish Docker image (${{ matrix.variant }})
153161
needs:
@@ -172,6 +180,11 @@ jobs:
172180
image: ghcr.io/kreuzberg-dev/kreuzberg
173181
tag_suffix: ""
174182
extra_tag: "latest"
183+
- variant: cli
184+
dockerfile: docker/Dockerfile.cli
185+
image: ghcr.io/kreuzberg-dev/kreuzberg-cli
186+
tag_suffix: ""
187+
extra_tag: "latest"
175188
if: ${{ needs.prepare.outputs.release_docker == 'true' }}
176189
steps:
177190
- name: Checkout
@@ -195,27 +208,27 @@ jobs:
195208
uses: docker/setup-buildx-action@v3
196209

197210
- name: Skip because tag already exists
198-
if: ${{ needs.prepare.outputs.force_republish != 'true' && ((matrix.variant == 'core' && needs.check-docker.outputs.core_exists == 'true') || (matrix.variant == 'full' && needs.check-docker.outputs.full_exists == 'true')) }}
211+
if: ${{ needs.prepare.outputs.force_republish != 'true' && ((matrix.variant == 'core' && needs.check-docker.outputs.core_exists == 'true') || (matrix.variant == 'full' && needs.check-docker.outputs.full_exists == 'true') || (matrix.variant == 'cli' && needs.check-docker.outputs.cli_exists == 'true')) }}
199212
run: echo "Docker tag already exists for variant ${{ matrix.variant }}; skipping publish." >> "$GITHUB_STEP_SUMMARY"
200213

201214
- name: Build AMD64 test image
202-
if: ${{ needs.prepare.outputs.force_republish == 'true' || (matrix.variant == 'core' && needs.check-docker.outputs.core_exists != 'true') || (matrix.variant == 'full' && needs.check-docker.outputs.full_exists != 'true') }}
215+
if: ${{ needs.prepare.outputs.force_republish == 'true' || (matrix.variant == 'core' && needs.check-docker.outputs.core_exists != 'true') || (matrix.variant == 'full' && needs.check-docker.outputs.full_exists != 'true') || (matrix.variant == 'cli' && needs.check-docker.outputs.cli_exists != 'true') }}
203216
run: docker build -f ${{ matrix.dockerfile }} --build-arg PDFIUM_VERSION=${{ env.PDFIUM_VERSION }} --build-arg ONNXRUNTIME_VERSION=${{ env.ORT_VERSION }} -t kreuzberg-publish:${{ matrix.variant }}-test .
204217

205218
- name: Run Docker feature tests
206-
if: ${{ needs.prepare.outputs.force_republish == 'true' || (matrix.variant == 'core' && needs.check-docker.outputs.core_exists != 'true') || (matrix.variant == 'full' && needs.check-docker.outputs.full_exists != 'true') }}
219+
if: ${{ needs.prepare.outputs.force_republish == 'true' || (matrix.variant == 'core' && needs.check-docker.outputs.core_exists != 'true') || (matrix.variant == 'full' && needs.check-docker.outputs.full_exists != 'true') || (matrix.variant == 'cli' && needs.check-docker.outputs.cli_exists != 'true') }}
207220
run: ./scripts/test_docker.sh --skip-build --image kreuzberg-publish:${{ matrix.variant }}-test --variant ${{ matrix.variant }} --verbose
208221

209222
- name: Log in to GitHub Container Registry
210-
if: ${{ needs.prepare.outputs.dry_run != 'true' && (needs.prepare.outputs.force_republish == 'true' || (matrix.variant == 'core' && needs.check-docker.outputs.core_exists != 'true') || (matrix.variant == 'full' && needs.check-docker.outputs.full_exists != 'true')) }}
223+
if: ${{ needs.prepare.outputs.dry_run != 'true' && (needs.prepare.outputs.force_republish == 'true' || (matrix.variant == 'core' && needs.check-docker.outputs.core_exists != 'true') || (matrix.variant == 'full' && needs.check-docker.outputs.full_exists != 'true') || (matrix.variant == 'cli' && needs.check-docker.outputs.cli_exists != 'true')) }}
211224
uses: docker/login-action@v3
212225
with:
213226
registry: ghcr.io
214227
username: ${{ github.actor }}
215228
password: ${{ secrets.GITHUB_TOKEN }}
216229

217230
- name: Extract Docker metadata
218-
if: ${{ needs.prepare.outputs.dry_run != 'true' && (needs.prepare.outputs.force_republish == 'true' || (matrix.variant == 'core' && needs.check-docker.outputs.core_exists != 'true') || (matrix.variant == 'full' && needs.check-docker.outputs.full_exists != 'true')) }}
231+
if: ${{ needs.prepare.outputs.dry_run != 'true' && (needs.prepare.outputs.force_republish == 'true' || (matrix.variant == 'core' && needs.check-docker.outputs.core_exists != 'true') || (matrix.variant == 'full' && needs.check-docker.outputs.full_exists != 'true') || (matrix.variant == 'cli' && needs.check-docker.outputs.cli_exists != 'true')) }}
219232
id: docker_meta
220233
uses: docker/metadata-action@v5
221234
with:
@@ -225,7 +238,7 @@ jobs:
225238
type=raw,value=${{ matrix.extra_tag }}
226239
227240
- name: Build and push image
228-
if: ${{ needs.prepare.outputs.dry_run != 'true' && (needs.prepare.outputs.force_republish == 'true' || (matrix.variant == 'core' && needs.check-docker.outputs.core_exists != 'true') || (matrix.variant == 'full' && needs.check-docker.outputs.full_exists != 'true')) }}
241+
if: ${{ needs.prepare.outputs.dry_run != 'true' && (needs.prepare.outputs.force_republish == 'true' || (matrix.variant == 'core' && needs.check-docker.outputs.core_exists != 'true') || (matrix.variant == 'full' && needs.check-docker.outputs.full_exists != 'true') || (matrix.variant == 'cli' && needs.check-docker.outputs.cli_exists != 'true')) }}
229242
uses: docker/build-push-action@v6
230243
with:
231244
context: .

0 commit comments

Comments
 (0)