Ich zeige hier eine GitHub Action für Dune Package Management mit ocaml-dune/setup-dune.
Das hier ist ein kurzes, praktisches Setup. Ich nutze es für OCaml-Repos, die dune pkg verwenden. Ich checke das dune.lock-Verzeichnis nicht ein, wie aktuell von den Dune Maintainers empfohlen.
Minimaler Workflow
Erstelle .github/workflows/ci.yml:
name: CI
on:
push:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Dune and build
uses: ocaml-dune/setup-dune@v2
Das installiert Dune, baut die Dependencies, baut dein Projekt und führt die Tests aus.
Cache-Strategie
Die Action cached den Dune-Cache und _build via actions/cache. Der Cache-Key enthält dune-project, die Dune-Version, OS, Arch und den Commit-SHA, und sie versucht einen Restore über Prefix. Der Key enthält weiterhin den SHA - du steuerst also vor allem das Restore-Verhalten.
Das ist okay, aber ich will, dass Restores an Dependency-Änderungen hängen, nicht an jedem Commit. In Docker erreiche ich das, indem ich den Compiler- und Dependency-Layer hinter dune-project und dune.lock isoliere - siehe A Practical Docker Cache Pattern for Dune Package Management. In GitHub Actions packe ich ein Dependency-Signal in den Cache-Prefix, damit die Restore-Keys über Source-Änderungen stabil bleiben.
- name: Install Dune and build
uses: ocaml-dune/setup-dune@v2
with:
cache-prefix: v1-${{ hashFiles('dune-project', 'dune-workspace.ci') }}
Damit bleiben die Restore-Keys stabil und der Cache wird an eine konkrete Dependency-Konfiguration gebunden. Ich pinne den opam repository Commit, damit die Builds wirklich reproduzierbar sind - sonst kann sich das opam repository unter dir verändern, und derselbe Commit zieht an unterschiedlichen Tagen andere Paketversionen. Das erzeugt außerdem leicht einen lokalen/CI-Mismatch: lokal löst du neuere Dependencies auf, während CI noch einen älteren Cache wiederverwendet. Eine einfache Variante ist, den opam repository Commit in einer Workspace-Datei zu pinnen - so wie ocaml.org es macht.
Wenn du die OCaml-Version selbst pinnen willst, halte das in dune-project, nicht im Workspace.
(package
(name dein_paket)
(depends
(ocaml (= 5.3.0))))
(repository
(name pinned_opam_repository)
(url git+https://github.com/ocaml/opam-repository#584630e7a7e27e3cf56158696a3fe94623a0cf4f))
Vollständiges Beispiel: github.com/ocaml/ocaml.org/.../dune-workspace
Im Beispiel-Repo ist die CI-Buildzeit nach dem Aufwärmen des Caches von etwa 3 Minuten auf 23 Sekunden gefallen. Die neuesten Commits zeigen den Unterschied zwischen Cache-Miss und Cache-Hit: github.com/sabine/dune-pkg-github-actions-example/commits/main.
Wenn du immer die neuesten opam-repository-Pakete willst, lass den Pin weg und rechne mit Solver-Churn, während sich das Repo bewegt. Cache-Hits können veraltet sein, solange dein Key dune.lock (oder ähnliches) nicht berücksichtigt. Ich bevorzuge Stabilität in CI und aktualisiere den Pin manuell.
Optional: Schritte kürzen
Wenn du nicht alle Schritte brauchst, kannst du eine eigene Liste angeben. Ich lasse normalerweise die Defaults, außer ich optimiere für Speed auf macOS.
- name: Install Dune and build
uses: ocaml-dune/setup-dune@v2
with:
steps: install-dune enable-pkg build-deps build runtest
Notes
- GitHub Action repo: github.com/ocaml-dune/setup-dune
- Dune Package Management docs: dune.readthedocs.io
- Wenn du stable Dune statt nightly willst, setze
version: latest.
Das ist es. Die bestehende ocaml-dune/setup-dune Action erledigt den Build, und der Cache Prefix hält das CI schnell, ohne zusätzliches Tooling.
Das ist mein persönliches Setup. Es ist keine Empfehlung der Dune Maintainers.
