waterui 0.5.1

A modern UI framework for Rust
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
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
name: Test

on:
  workflow_call:
    inputs:
      # `false` is the fast gate: format and default-features workspace clippy.
      # `true` is the nightly matrix: every test, example, doctest, platform,
      # optional-feature lint pass and the skill compile gate. Dev pushes
      # enter through dev.yml; pull requests keep the additional ABI and
      # dependency checks in ci.yml. Both callers use the same fast lint.
      full:
        type: boolean
        default: false

env:
  CARGO_TERM_COLOR: always
  # cargo/rustup retry network failures three times by default; ten
  # matches the budget install-action sets for its own downloads.
  CARGO_NET_RETRY: "10"
  RUSTUP_MAX_RETRIES: "10"
  # rust-cache and the install-tool binary caches are the only cache
  # layers (see the note in ci.yml).
  CARGO_INCREMENTAL: 0
  WATERUI_TEST_ARTIFACTS_DIR: ${{ github.workspace }}/test-artifacts

# Parallel jobs instead of one serial leg per platform (#329), with the
# examples compiled once in their own job (#330). The cargo passes
# below used to run one after another inside a single job per OS, which put
# every clippy shape in front of the ubuntu tests and every macOS-only suite
# behind the macOS workspace run; the macOS leg was the critical path of every
# CI run.
#
# Two tiers (#379). Every all-features pass is a second `-C metadata` profile
# of the whole workspace that no cache can hold next to the default one, so
# it is a 35-40 minute cold build on every platform, every run, and it made
# every pull request a 60-70 minute wait whatever it changed. Those passes,
# the macOS platform and the macOS suites now run only when `full` is set,
# which `nightly.yml` does once a day against `dev`; a pull request and a
# push to `dev` run default-features clippy and format on Linux (#458).
# The complete default-feature tests and examples also belong to nightly;
# no test coverage is removed to shorten the per-change feedback loop.
jobs:
  # Lint before testing: it is the cheapest failure to produce, and the one a
  # contributor is most likely to hit, so it should not wait behind the whole
  # test run — nor should the test run wait behind it. Linux only; the macOS
  # CEF lint lives in `cef`, because that target refuses to compile anywhere
  # else.
  lint:
    name: lint
    runs-on: ubuntu-latest
    timeout-minutes: ${{ inputs.full && 90 || 10 }}
    steps:
      - uses: actions/checkout@v4
      # The fast gate owns the target-cache budget, including workspace check
      # artifacts. Only integration-branch fast runs write it; pull requests
      # and the full nightly lint restore without adding cache generations.
      # The check-only Cargo profile avoids optimizing build dependencies for
      # runtime speed when this job only needs their compiler output.
      - uses: ./.github/actions/setup-rust
        with:
          components: clippy, rustfmt
          shared-key: lint-${{ runner.os }}
          cache-targets: true
          cache-workspace-crates: true
          save-if: ${{ !inputs.full && (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main') }}
      - name: Install native dependencies
        uses: ./.github/actions/setup-linux-deps
      - name: Format
        run: cargo fmt --all -- --check
      # Workspace-wide under default features first: it is the cheapest of the
      # lint passes and the one every crate's normal build shape goes through.
      # `--all-targets` in the fast shape too: the gate runs no test, but a
      # `#[cfg(test)]` module or a `tests/` target that no longer compiles
      # must not wait for the nightly to be noticed.
      - name: Clippy (workspace)
        run: cargo clippy --locked --profile ci-check --workspace --exclude '*-example' --all-targets -- -D warnings
      # Then every crate's own optional features. This pass used to be
      # `cargo clippy --all-targets --all-features`, with neither `-p` nor
      # `--workspace`: the root manifest carries both `[workspace]` and
      # `[package]`, so cargo narrowed it to the root `waterui` crate, and a
      # backend's own non-default features were linted only where the root
      # happened to enable them. Nothing in CI compiled dew's
      # `embedded-simulator` / `espidf`, gtk's `webkitgtk`, or the browsers'
      # engine features at all (#261).
      #
      # `--workspace --all-features` covers all of those. Three crates cannot
      # join it, because `--all-features` asks for feature sets that are
      # mutually exclusive by construction; each is excluded here and linted
      # below in the shapes it actually has. Every one of the three is still
      # linted under its default features by the workspace pass above, and the
      # steps share this job's target dir, so each is an increment on a graph
      # that is already built.
      - name: Clippy (all features, workspace)
        if: inputs.full
        run: |
          cargo clippy --locked --profile ci-check --workspace --all-targets --all-features \
            --exclude '*-example' \
            --exclude waterui-core \
            --exclude waterui-ffi \
            --exclude waterui-browser-cef \
            -- -D warnings
      # `waterui-core`'s `nightly` feature turns on `feature(never_type)`, which
      # is a hard E0554 on the stable channel this job pins. Everything else the
      # crate has, it gets here.
      - name: Clippy (waterui-core, every stable feature)
        if: inputs.full
        run: cargo clippy --locked --profile ci-check -p waterui-core --all-targets --features std,serde -- -D warnings
      # `waterui-ffi` selects its ABI with mutually exclusive features and
      # `ffi/src/lib.rs` turns `c-api` + `android-jni` into a `compile_error!`.
      # This is the `c-api` half with every optional C surface a runtime build
      # can carry; the `android-jni` half is the `Android FFI` job in ci.yml,
      # and the compile-only `cef-header` shape is the `cef` job below.
      - name: Clippy (waterui-ffi, C ABI surfaces)
        if: inputs.full
        run: cargo clippy --locked --profile ci-check -p waterui-ffi --all-targets --features map,chromium,webview-cef -- -D warnings
      # `compile-only` swaps in CEF's `dox` stubs and stops the build script
      # downloading the distribution that `cef-runtime` — and the `real_engine`
      # test target — need, so the two can never be enabled together. This is
      # the runtime shape, which nothing else lints: the macOS `real-engine`
      # pass has no `chromium`, and its `cef-header` pass is `compile-only`.
      # `real-engine` stays off here because that test target is macOS-only;
      # `--all-targets` skips it for want of its required feature.
      - name: Clippy (waterui-browser-cef, CEF runtime)
        if: inputs.full
        run: cargo clippy --locked --profile ci-check -p waterui-browser-cef --all-targets --features chromium,webview -- -D warnings
      # The waterui skill's snippet compile gate: every rust fence in
      # .claude/skills/waterui is transcribed into .claude/skills/waterui/skill_snippets
      # and must keep compiling. The non-default feature exposes the test/bench
      # transcriptions to the compiler without registering runnable tests —
      # they address elements that do not exist by design and must never run.
      - name: Skill snippet compile gate
        if: inputs.full
        run: cargo check --locked --profile ci-check -p skill_snippets --all-targets --features compile-gate-tests

  # The crates whose wasm-only paths nothing else compiles.
  #
  # Every other leg builds them for the host, where everything under
  # `cfg(target_arch = "wasm32")` is compiled out — so the browser build rotted
  # through three unrelated breakages before anyone pointed a compiler at it
  # (#408). `waterui-media` reads local photos through the waterkit file
  # system there. The web runner that
  # used to lead this list is Hydrolysis', and its own repository lints it for
  # wasm32 (#480).
  #
  # It lints rather than merely compiles, so `cfg(target_arch = "wasm32")` code
  # is held to the same bar as every other target (#413).
  #
  # This target-specific pass runs nightly alongside the other platform
  # shapes (#458). The fast gate retains default-feature host clippy; the
  # nightly still checks the actual wasm-only code.
  wasm:
    name: wasm32
    if: inputs.full
    runs-on: ubuntu-latest
    timeout-minutes: 45
    env:
      # Cargo caps lints for registry dependencies, so this holds the workspace
      # crates — and only them — to the same "no new warnings" bar as the host
      # lint pass. It reaches further than the trailing `-- -D warnings` below,
      # which only covers the packages named with `-p`.
      RUSTFLAGS: -D warnings
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/setup-rust
        with:
          targets: wasm32-unknown-unknown
          shared-key: cargo-home-${{ runner.os }}
          cache-targets: false
          save-if: false
          cache-on-failure: true
      # Build scripts and proc macros still compile for the host even when
      # every library target is wasm, and this graph reaches the ones that need
      # native headers.
      - name: Install native dependencies
        uses: ./.github/actions/setup-linux-deps
      # `waterkit-dialog` is a registry crate now (its browser backend is
      # linted for wasm32 in water-rs/waterkit's own CI), so cargo caps its
      # lints; only the workspace crate is named here.
      - name: Lint the wasm32-only paths
        run: |
          cargo clippy --locked --profile ci-check --target wasm32-unknown-unknown \
            -p waterui-media \
            -- -D warnings

  # The workspace test run, per platform, also carrying the doctests that
  # share its build. It is the single longest leg in CI and everything else
  # overlaps it. The all-features pass is `all-features` below on Linux and
  # `macos-all-features` on macOS.
  test:
    name: ${{ matrix.os }}
    if: inputs.full
    runs-on: ${{ matrix.os }}
    timeout-minutes: 120
    strategy:
      # Report every platform in one run. Cancelling the other hides its
      # results, so a cross-platform break costs one round trip per platform.
      fail-fast: false
      matrix:
        # Windows is kept in its own workflow because it needs platform-
        # specific exclusions and compile-only CEF coverage; `nightly.yml`
        # calls it beside this one. This job runs only when `full` is set, so
        # both platforms are always in the matrix.
        os: ["ubuntu-latest", "macos-latest"]
    steps:
      - uses: actions/checkout@v4
      # The nightly test profiles restore only Cargo sources. Their multi-GB
      # target archives previously occupied the cache budget while every dev
      # push cold-compiled clippy. The frequent lint gate now owns that budget;
      # these daily runs keep every test without evicting its check artifacts.
      - uses: ./.github/actions/setup-rust
        with:
          shared-key: cargo-home-${{ runner.os }}
          cache-targets: false
          save-if: false
          cache-on-failure: true
      # GPU snapshot tests run in this job, so this leg needs the Vulkan ICD
      # loader (mesa-vulkan-drivers/libvulkan1) on top of the base package
      # list — that's what lets llvmpipe/lavapipe stand in for a real GPU on
      # a headless Linux runner.
      - name: Install native dependencies
        if: runner.os == 'Linux'
        uses: ./.github/actions/setup-linux-deps
        with:
          gpu: "true"
      - uses: ./.github/actions/install-tool
        with:
          tool: cargo-nextest@0.9.145
          path: ~/.cargo/bin/cargo-nextest*
      # One full-workspace pass under default features. Every crate's own
      # optional features are the `all-features` job below (Linux) and
      # `macos-all-features` (macOS). The `trybuild_*` macro contract tests run
      # only here — each shells out to a fixture build that does not depend on
      # the outer feature set, so the all-features passes and coverage skip
      # them (see below).
      - run: cargo nextest run --locked --workspace --exclude '*-example' --profile ci
      # nextest cannot run doctests, and this workspace has plenty of them.
      - run: cargo test --locked --doc --workspace --exclude '*-example'
      - name: Upload Test Snapshots
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-snapshots-${{ matrix.os }}
          path: test-artifacts/
          if-no-files-found: ignore
          retention-days: 14

  # Every crate's own optional features, run. This pass used to be
  # `cargo nextest run --locked --all-features` inside the `test` job, with neither
  # `-p` nor `--workspace`: the root manifest carries both `[workspace]` and
  # `[package]`, so cargo narrowed it to the root `waterui` crate, and a
  # backend crate's tests behind its own optional features — dew's
  # `embedded-simulator`, the browsers' engine features — ran nowhere
  # (#276, the test-side twin of
  # #261). It is its own job for the same reason the clippy sweep is a
  # separate step: a second feature variant of the dependency graph is a
  # second codegen of most of the workspace, and it overlaps the workspace
  # pass here instead of queueing behind it.
  #
  # Same three exclusions as the clippy sweep in `lint`, for the same reason:
  # `--all-features` asks those crates for feature sets that are mutually
  # exclusive by construction. Each is run below in the shapes it actually
  # has, sharing this job's target dir.
  #
  # `skill_snippets` is a fifth, on every platform: its `compile-gate-tests`
  # feature registers the skill's `#[waterui::test]` transcriptions as test
  # targets that address elements which do not exist by design and must never
  # run, and its `dev` feature turns on `waterui/dynamic_linking`. The lint
  # job compiles that crate in the shape it is meant to be compiled in.
  all-features:
    name: ubuntu-latest (all features)
    if: inputs.full
    runs-on: ubuntu-latest
    timeout-minutes: 120
    steps:
      - uses: actions/checkout@v4
      # Restore-only reader of the shared Linux `~/.cargo` tarball (see the
      # cache budget note in ci.yml).
      - uses: ./.github/actions/setup-rust
        with:
          shared-key: cargo-home-${{ runner.os }}
          cache-targets: false
          save-if: false
          cache-on-failure: true
      # GPU snapshot tests run under these features too, so this leg needs
      # the Vulkan ICD loader the way `test` does.
      - name: Install native dependencies
        uses: ./.github/actions/setup-linux-deps
        with:
          gpu: "true"
      - uses: ./.github/actions/install-tool
        with:
          tool: cargo-nextest@0.9.145
          path: ~/.cargo/bin/cargo-nextest*
      # The `trybuild_*` binaries each drive a cold fixture build of the
      # framework that is independent of the outer feature set; they already
      # ran once in the default-features `test` job on this OS, so this pass
      # skips them while keeping the rest of the two crates' tests.
      - name: Test (all features, workspace)
        run: |
          cargo nextest run --locked --workspace --all-features --profile ci \
            --exclude '*-example' \
            --exclude waterui-core \
            --exclude waterui-ffi \
            --exclude waterui-browser-cef \
            --exclude skill_snippets \
            -E 'not binary(/^trybuild_/)'
      # `nightly` is `feature(never_type)`, a hard E0554 on stable.
      - name: Test (waterui-core, every stable feature)
        run: cargo nextest run --locked -p waterui-core --features std,serde --profile ci
      # The `c-api` half with every optional C surface a runtime build can
      # carry; `android-jni` is the `Android FFI` job in ci.yml.
      - name: Test (waterui-ffi, C ABI surfaces)
        run: cargo nextest run --locked -p waterui-ffi --features map,chromium,webview-cef --profile ci
      # The CEF runtime shape; `compile-only` and `real-engine` exclude it.
      - name: Test (waterui-browser-cef, CEF runtime)
        run: cargo nextest run --locked -p waterui-browser-cef --features chromium,webview --profile ci
      - name: Upload Test Snapshots
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-snapshots-ubuntu-latest-all-features
          path: test-artifacts/
          if-no-files-found: ignore
          retention-days: 14

  # The macOS all-features pass: every crate's own optional features, with the
  # same exclusions as the Linux `all-features` job (see there). It used to
  # share a serial `macos-suites` job with the doctests and the CEF legs; the
  # three have nothing in common but the platform, so each is its own job and
  # the doctests moved into `test`, whose build they share.
  macos-all-features:
    name: macos-latest (all features)
    if: inputs.full
    runs-on: macos-latest
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v4
      # Writes the macOS `~/.cargo` tarball for the macOS jobs that store no
      # target directory (see the cache budget note in ci.yml).
      - uses: ./.github/actions/setup-rust
        with:
          shared-key: cargo-home-${{ runner.os }}
          cache-targets: false
          save-if: ${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' }}
          cache-on-failure: true
      - uses: ./.github/actions/install-tool
        with:
          tool: cargo-nextest@0.9.145
          path: ~/.cargo/bin/cargo-nextest*
      # Of the excluded crates, `waterui-core`'s stable feature shape runs
      # below; the FFI C surfaces and the CEF runtime shape are
      # host-independent and the Linux job covers them, and the compile-only
      # `cef-header` shape is the `cef` job. The `trybuild_*` macro contract
      # tests ran already in `test` on this OS; see there.
      - name: Test (all features, workspace)
        run: |
          cargo nextest run --locked --workspace --all-features --profile ci \
            --exclude '*-example' \
            --exclude waterui-core \
            --exclude waterui-ffi \
            --exclude waterui-browser-cef \
            --exclude skill_snippets \
            -E 'not binary(/^trybuild_/)'
      - name: Test (waterui-core, every stable feature)
        run: cargo nextest run --locked -p waterui-core --features std,serde --profile ci
      - name: Upload Test Snapshots
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-snapshots-macos-all-features
          path: test-artifacts/
          if-no-files-found: ignore
          retention-days: 14

  # The macOS-only CEF legs. The web view bridge has broken three times in
  # ways no Rust-side test could see, so these drive a real Chromium. CEF is a
  # prebuilt distribution `cef-dll-sys` downloads while building the crate.
  # macOS only, because CEF requires its browser process to live in an
  # application bundle; the test stages one and the target does not compile on
  # the other platforms.
  #
  # This was the tail of `macos-suites`, sharing the workspace build the
  # all-features pass had already paid for. Splitting it out pays a second
  # build of just the CEF subtree in exchange for taking it off the critical
  # path: the clippy pass and the real-engine test overlap the macOS test jobs
  # instead of queueing behind a 35-40 minute all-features compile.
  cef:
    name: cef (macos-latest)
    if: inputs.full
    runs-on: macos-latest
    timeout-minutes: 90
    steps:
      - uses: actions/checkout@v4
      # Restore-only reader of the shared macOS `~/.cargo` tarball, written by
      # `macos-all-features` (see the cache budget note in ci.yml). clippy is
      # needed by the CEF real-engine target, which cannot be linted on Linux
      # because CEF requires a macOS application bundle.
      - uses: ./.github/actions/setup-rust
        with:
          components: clippy
          shared-key: cargo-home-${{ runner.os }}
          cache-targets: false
          save-if: false
          cache-on-failure: true
      # The same step also lints the FFI crate's compile-only CEF C ABI, which
      # no other leg reaches: the Linux all-features passes exclude
      # `waterui-ffi` for its ABI `compile_error!` and lint the `cef-runtime`
      # shape instead, and `cef-header` is the mutually exclusive
      # `compile-only` one. macOS is also the only leg that sees its
      # `#[cfg(target_os = "macos")]` entry points at all, and the compile-only
      # feature set buys the lint without a CEF runtime download.
      - name: Lint the CEF targets
        run: |
          cargo clippy --locked --profile ci-check -p waterui-browser-cef --features real-engine --all-targets -- -D warnings
          cargo clippy --locked --profile ci-check -p waterui-ffi --features cef-header --all-targets -- -D warnings
      # `cargo test` rather than nextest: CEF's browser process has to own the
      # main thread, libtest runs test bodies on spawned ones, so the target is
      # `harness = false` and nextest cannot enumerate it.
      - name: Run the CEF real-engine tests
        run: cargo test --locked -p waterui-browser-cef --features real-engine --test real_engine
      - name: Upload Test Snapshots
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-snapshots-cef
          path: test-artifacts/
          if-no-files-found: ignore
          retention-days: 14

  # The 36 example crates, once per platform (#330). They used to be workspace
  # members in every pass above, so each example was compiled under every
  # clippy shape and again for the tests; here they get the passes they
  # actually need — lint, tests, doctests — and nothing else builds them.
  # Linux lints them; macOS never did (its leg ran no clippy on the
  # workspace), and that stays as it was.
  examples:
    name: examples (${{ matrix.os }})
    if: inputs.full
    runs-on: ${{ matrix.os }}
    timeout-minutes: 90
    strategy:
      fail-fast: false
      matrix:
        # Gated on `full` like `test` above, so both platforms always run.
        os: ["ubuntu-latest", "macos-latest"]
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/setup-rust
        with:
          components: clippy
          shared-key: cargo-home-${{ runner.os }}
          cache-targets: false
          save-if: ${{ runner.os == 'Linux' && (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main') }}
          cache-on-failure: true
      # Examples carry GPU snapshot tests too, so the Linux leg needs the same
      # Vulkan ICD loader the `test` job installs.
      - name: Install native dependencies
        if: runner.os == 'Linux'
        uses: ./.github/actions/setup-linux-deps
        with:
          gpu: "true"
      - uses: ./.github/actions/install-tool
        with:
          tool: cargo-nextest@0.9.145
          path: ~/.cargo/bin/cargo-nextest*
      - name: Clippy (examples)
        if: runner.os == 'Linux'
        run: cargo clippy --locked --profile ci-check -p '*-example' --all-targets -- -D warnings
      - run: cargo nextest run --locked -p '*-example' --profile ci
      - run: cargo test --locked --doc -p '*-example'
      - name: Upload Test Snapshots
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-snapshots-examples-${{ matrix.os }}
          path: test-artifacts/
          if-no-files-found: ignore
          retention-days: 14