Skip to content

Building Testing and CI

Nikolai Sachok edited this page Jun 24, 2026 · 2 revisions

Building, Testing & CI

Build

One script per plugin, no hidden state. markdown-wlx/build.sh:

clang -dynamiclib -arch arm64 -arch x86_64 \
  -mmacosx-version-min=11.0 -fobjc-arc -fvisibility=hidden -O2 \
  -framework Cocoa -framework WebKit \
  -o build/MarkdownView.wlx MarkdownView.m
codesign --force --sign - build/MarkdownView.wlx     # ad-hoc
  • Universal via two -arch flags → one fat Mach-O. Verify: lipo -archs <file>.
  • -fvisibility=hidden keeps the export surface minimal; the five WLX functions are explicitly marked __attribute__((visibility("default"))).
  • -fobjc-arc — ARC on, with explicit bridging where objects cross the C ABI (see WLX Plugin Model).
  • Ad-hoc codesign -s - is enough because the host has no library validation.

Tests — load the real artifact

The harnesses in test/ dlopen the built .wlx and call the exact ABI Double Commander uses. Testing the real binary (not a mock) is what makes them trustworthy.

Harness Asserts
test_host.m the plugin renders — #content gains children after marked.parse
snap_host.m saves a PNG snapshot of the rendered output (visual check)
esc_verify.m end-to-end: focus the web view, send Escape, assert the host view receives it
esc_probe.m the diagnostic probe that located the Escape root cause
scroll_verify.m scroll a file, navigate away and back, assert the offset is restored

Build & run one:

clang -arch arm64 -fobjc-arc -framework Cocoa -framework WebKit \
    -o build/test_host test/test_host.m
cp -R assets build/assets          # assets must sit next to the .wlx
./build/test_host build/MarkdownView.wlx test/sample.md     # → RESULT: PASS

These are GUI-bound (they spin up WKWebView / an NSWindow), so they run locally, not on the headless CI runner.

CI (.github/workflows/ci.yml)

Two jobs, both deterministic:

  • leak-guard (Ubuntu) — runs scripts/leak-guard.sh: the generic secret / private-path / OS-cruft gate. Fails the build on any hit.
  • build (macOS) — runs build.sh, then asserts:
    • the binary is universal (lipo -archs contains both arm64 and x86_64),
    • all five WLX entry points are exported (nm -gU).

CI intentionally checks the build + ABI rather than the GUI render — those checks are fast and never flake, while the render/Escape tests stay as local verification.

Releases

Tagging markdown-wlx-v* triggers .github/workflows/release.yml: it builds the universal plugin, assembles a no-Xcode install bundle (the .wlx + assets/ + install.sh + a sample config), and publishes a zip + SHA-256 to GitHub Releases. install.sh detects the prebuilt .wlx beside it and skips the build step, so non-developers can install without a toolchain.

The layered safety gate

scripts/leak-guard.sh is generic by design — secrets, /Users|/home absolute paths, private keys, OS cruft. It deliberately does not enumerate any business/domain terms, because a public checker that lists sensitive words would itself leak them. Domain-specific auditing, if any, belongs in a private gate run before push. Wire the generic gate locally as a pre-commit hook:

ln -sf ../../scripts/leak-guard.sh .git/hooks/pre-commit

Clone this wiki locally