← Zurück zum BlogENRead in English

Dune Package Management auf GitHub Actions: ein praktisches Setup

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

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.