-
Notifications
You must be signed in to change notification settings - Fork 3
374 lines (332 loc) · 15.9 KB
/
Copy pathci.yml
File metadata and controls
374 lines (332 loc) · 15.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
name: CI
on:
push:
branches: [master]
pull_request:
branches: [master]
# Manual re-run from the Actions tab / `gh workflow run`. Left blank it runs lint
# + test only; set `force_version` to (re)publish that exact version — use it to
# release a version a failed/blocked run skipped (e.g. the master-ruleset reject).
workflow_dispatch:
inputs:
force_version:
description: "Force a release at this exact version (e.g. 0.3.0). Blank = lint+test only, no publish."
required: false
default: ""
# Cancel superseded PR runs, but never interrupt a master run (it may publish).
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
CARGO_TERM_COLOR: always
# Keep target/ small enough to cache and restore: no incremental artifacts
# (useless for one-shot CI builds, gigabytes on disk) and no debuginfo in
# dev/test binaries (the bulk of a debug target; tests behave the same,
# backtraces just lose line numbers). Without this the cached target/ grew
# past 6 GB compressed (~20 GB unpacked) and cache *restore* started dying
# with ENOSPC on the runner disk — which is also why every cache key below
# carries a `v2` generation: the old oversized entries must never match.
CARGO_INCREMENTAL: "0"
CARGO_PROFILE_DEV_DEBUG: "0"
CARGO_PROFILE_TEST_DEBUG: "0"
# Rust version for the style/lint gates. Pinned on purpose: rustfmt and clippy
# change their output/lints between releases, so a floating `stable` would let
# a new toolchain fail CI on otherwise-unrelated commits. Bump this manually
# (and fix any new findings in the same PR) when you want to adopt a newer one.
LINT_TOOLCHAIN: "1.96.0"
jobs:
lint:
name: fmt · clippy (pinned)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
# rustup is preinstalled on GitHub-hosted runners; use it directly rather
# than a marketplace toolchain action (the docling-project org allowlists
# only GitHub-owned / vetted actions).
- name: Install Rust ${{ env.LINT_TOOLCHAIN }}
run: |
rustup toolchain install ${{ env.LINT_TOOLCHAIN }} --profile minimal --component rustfmt --component clippy
rustup default ${{ env.LINT_TOOLCHAIN }}
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
target
key: ${{ runner.os }}-cargo-v2-lint-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-v2-lint-
- name: Format
run: cargo fmt --all --check
- name: Clippy
run: cargo clippy --workspace --all-targets -- -D warnings
# actions/cache saves target/ in its post-step, i.e. after this runs:
# drop what is cheap to recreate (incremental data shouldn't exist with
# CARGO_INCREMENTAL=0; examples and final bin-crate executables relink
# in seconds — the compiled library deps are what's worth keeping), so
# the cache stays well under the runner's disk headroom.
- name: Trim target before cache save
if: always()
shell: bash
run: |
rm -rf target/debug/examples target/debug/incremental \
target/release/examples target/release/incremental
find target/debug target/release -maxdepth 1 -type f ! -name '*.d' -size +5M -exec rm -f {} + 2>/dev/null || true
test:
name: test (stable)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
# Tests stay on the current stable so they catch real compiler breakage.
- name: Install Rust (stable)
run: |
rustup toolchain install stable --profile minimal
rustup default stable
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
target
key: ${{ runner.os }}-cargo-v2-test-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-v2-test-
# Pure-Rust unit tests + the output-regression suite. The PDF/image/METS
# snapshot tests need pdfium + the ONNX models, so they are NOT run here —
# this job downloads no ML models and stays fast. --locked doubles as the
# guard that keeps the committed Cargo.lock in sync with the manifests
# (a Cargo.toml change without its lock update fails here).
- name: Test
run: cargo test --workspace --locked
# actions/cache saves target/ in its post-step, i.e. after this runs:
# drop what is cheap to recreate (incremental data shouldn't exist with
# CARGO_INCREMENTAL=0; examples and final bin-crate executables relink
# in seconds — the compiled library deps are what's worth keeping), so
# the cache stays well under the runner's disk headroom.
- name: Trim target before cache save
if: always()
shell: bash
run: |
rm -rf target/debug/examples target/debug/incremental \
target/release/examples target/release/incremental
find target/debug target/release -maxdepth 1 -type f ! -name '*.d' -size +5M -exec rm -f {} + 2>/dev/null || true
# Validate the declared `rust-version` floors against the committed
# Cargo.lock (rust-lang.org/2023/08/29/committing-lockfiles: a committed
# lock is what makes MSRV checkable at all). Two tiers: docling-core keeps a
# lower floor (no ort/pdfium), the rest of the workspace sits at the ort
# floor. Keep these toolchains in sync with the `rust-version` values in the
# manifests — a weekly dependency-update PR that pulls a dep with a higher
# floor turns this job red, forcing a conscious pin or floor bump.
msrv:
name: msrv (1.85 core · 1.88 workspace)
runs-on: ubuntu-latest
env:
MSRV_CORE: "1.85"
MSRV_WORKSPACE: "1.88"
steps:
- uses: actions/checkout@v7
- name: Install Rust ${{ env.MSRV_CORE }} + ${{ env.MSRV_WORKSPACE }}
run: rustup toolchain install ${{ env.MSRV_CORE }} ${{ env.MSRV_WORKSPACE }} --profile minimal
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
target
key: ${{ runner.os }}-cargo-v2-msrv-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-v2-msrv-
- name: Check docling-core on ${{ env.MSRV_CORE }}
run: cargo +${{ env.MSRV_CORE }} check -p docling-core --locked
- name: Check workspace on ${{ env.MSRV_WORKSPACE }}
run: cargo +${{ env.MSRV_WORKSPACE }} check --workspace --locked
# actions/cache saves target/ in its post-step, i.e. after this runs:
# drop what is cheap to recreate (incremental data shouldn't exist with
# CARGO_INCREMENTAL=0; examples and final bin-crate executables relink
# in seconds — the compiled library deps are what's worth keeping), so
# the cache stays well under the runner's disk headroom.
- name: Trim target before cache save
if: always()
shell: bash
run: |
rm -rf target/debug/examples target/debug/incremental \
target/release/examples target/release/incremental
find target/debug target/release -maxdepth 1 -type f ! -name '*.d' -size +5M -exec rm -f {} + 2>/dev/null || true
# Build-verify the GPU execution-provider features (#74) without GPU
# runners: `cargo check` proves the feature plumbing and the EP registration
# code compile against the matching `ort` feature set. Each provider is
# checked on the platform its ONNX Runtime binaries exist for — actually
# *running* on GPU is out of scope for CI (no GPU hardware here).
ep-features:
name: check (${{ matrix.features }}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# `slug` is the features list with `-` instead of `,` — actions/cache
# rejects keys containing commas.
include:
- os: ubuntu-latest
features: cuda
slug: cuda
- os: ubuntu-latest
features: cuda,tensorrt
slug: cuda-tensorrt
- os: macos-latest
features: coreml
slug: coreml
- os: windows-latest
features: directml
slug: directml
steps:
- uses: actions/checkout@v7
- name: Install Rust (stable)
run: |
rustup toolchain install stable --profile minimal
rustup default stable
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
target
key: ${{ runner.os }}-cargo-v2-ep-${{ matrix.slug }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-v2-ep-${{ matrix.slug }}-
- name: Check docling-cli with GPU features
run: cargo check -p docling-cli --features "${{ matrix.features }}"
# docling-rag mirrors the same EP features (ingest conversion + the
# onnx-embed embedder session route through docling-pdf's ep module).
- name: Check docling-rag with GPU features
run: cargo check -p docling-rag --features "${{ matrix.features }},onnx-embed"
- name: Test docling-pdf EP selection with GPU features
run: 'cargo test -p docling-pdf --lib --features "${{ matrix.features }}" ep::'
# actions/cache saves target/ in its post-step, i.e. after this runs:
# drop what is cheap to recreate (incremental data shouldn't exist with
# CARGO_INCREMENTAL=0; examples and final bin-crate executables relink
# in seconds — the compiled library deps are what's worth keeping), so
# the cache stays well under the runner's disk headroom.
- name: Trim target before cache save
if: always()
shell: bash
run: |
rm -rf target/debug/examples target/debug/incremental \
target/release/examples target/release/incremental
find target/debug target/release -maxdepth 1 -type f ! -name '*.d' -size +5M -exec rm -f {} + 2>/dev/null || true
# The declarative converters compile for the browser (#79): check the
# feature-sliced `docling` on wasm32, build the wasm-bindgen crate, and log
# the gzipped module size (the number docs/README quote — ~1.9 MB).
wasm:
name: wasm32 (declarative converters)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Install Rust (stable + wasm32 target)
run: |
rustup toolchain install stable --profile minimal
rustup default stable
rustup target add wasm32-unknown-unknown
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
target
key: ${{ runner.os }}-cargo-v2-wasm-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-v2-wasm-
- name: Check docling (no default features) on wasm32
run: cargo check -p docling --no-default-features --target wasm32-unknown-unknown --locked
- name: Check docling (pdf-text) on wasm32
run: cargo check -p docling --no-default-features --features pdf-text --target wasm32-unknown-unknown --locked
- name: Build docling-wasm (release)
run: cargo build -p docling-wasm --target wasm32-unknown-unknown --release --locked
- name: Host-side tests
run: cargo test -p docling-wasm --locked
- name: Module size
run: |
wasm=target/wasm32-unknown-unknown/release/docling_wasm.wasm
gzip -9 -c "$wasm" | wc -c | xargs -I{} echo "docling_wasm.wasm: $(stat -c%s "$wasm") bytes raw, {} bytes gzipped"
# actions/cache saves target/ in its post-step, i.e. after this runs:
# drop what is cheap to recreate (incremental data shouldn't exist with
# CARGO_INCREMENTAL=0; examples and final bin-crate executables relink
# in seconds — the compiled library deps are what's worth keeping), so
# the cache stays well under the runner's disk headroom.
- name: Trim target before cache save
if: always()
shell: bash
run: |
rm -rf target/debug/examples target/debug/incremental \
target/release/examples target/release/incremental
find target/debug target/release -maxdepth 1 -type f ! -name '*.d' -size +5M -exec rm -f {} + 2>/dev/null || true
publish:
name: release & publish
needs: [lint, test]
if: >-
(github.event_name == 'push' && github.ref == 'refs/heads/master') ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.force_version != '')
runs-on: ubuntu-latest
permissions:
contents: write # push the version-bump commit + tag
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # full history + tags, for the semantic version bump
# Push the release commit + tag as an admin PAT so it satisfies the
# `master` ruleset; the default GITHUB_TOKEN can't be granted a bypass.
token: ${{ secrets.RELEASE_PAT }}
- name: Install Rust (stable)
run: |
rustup toolchain install stable --profile minimal
rustup default stable
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
target
key: ${{ runner.os }}-cargo-v2-publish-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-v2-publish-
# Decide the next version from conventional commits since the last tag (or
# use force_version on a manual dispatch); if there is one, bump + commit +
# tag it, push to master, and publish the crates (in dependency order,
# skipping any already on crates.io). A no-op when no release-worthy commit
# landed. The release commit is pushed with RELEASE_PAT (an admin token, so
# it satisfies the master ruleset) and carries [skip ci], so it does not
# re-trigger CI.
- name: Release & publish
id: release
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
FORCE_VERSION: ${{ github.event.inputs.force_version }}
run: bash scripts/ci/release.sh
# Cut a GitHub Release for the tag release.sh just pushed, using the commit
# list it assembled as the description. Skipped when the release step was a
# no-op (no release-worthy commits). Idempotent: if a release for the tag
# already exists (e.g. a forced re-publish), refresh its notes instead of
# failing.
- name: Create GitHub Release
if: steps.release.outputs.released == 'true'
env:
GH_TOKEN: ${{ secrets.RELEASE_PAT }}
run: |
tag="v${{ steps.release.outputs.version }}"
notes="${{ steps.release.outputs.notes_file }}"
if gh release view "$tag" >/dev/null 2>&1; then
gh release edit "$tag" --title "$tag" --notes-file "$notes"
else
gh release create "$tag" --title "$tag" --notes-file "$notes" --verify-tag
fi
# actions/cache saves target/ in its post-step, i.e. after this runs:
# drop what is cheap to recreate (incremental data shouldn't exist with
# CARGO_INCREMENTAL=0; examples and final bin-crate executables relink
# in seconds — the compiled library deps are what's worth keeping), so
# the cache stays well under the runner's disk headroom.
- name: Trim target before cache save
if: always()
shell: bash
run: |
rm -rf target/debug/examples target/debug/incremental \
target/release/examples target/release/incremental
find target/debug target/release -maxdepth 1 -type f ! -name '*.d' -size +5M -exec rm -f {} + 2>/dev/null || true