Automatically release OCaml packages to opam using dune-release in GitHub Actions workflows 🚀
New to automatic releasing? Check out the GUIDE.md for best practices on when to release, how to maintain your changelog, and a handy release script.
-
Fork opam-repository: You need a fork of ocaml/opam-repository in your GitHub account
- Go to https://github.com/ocaml/opam-repository/fork
- Create a fork (use default settings)
-
GitHub Token: Create a Personal Access Token (classic) with these scopes:
- ✅
repo- Full control of repositories - ✅
workflow- Update GitHub Action workflows - Add it to your repository secrets as
GH_TOKEN
- ✅
The action expects these tools to be available in your GitHub Actions environment:
opam- OCaml package managerdune-release- Release automation tool
Install with:
- uses: ocaml/setup-ocaml@v3
with:
ocaml-compiler: 5.3.0
- run: opam install dune-release -yname: Release
on:
push:
# Trigger this workflow when a tag is pushed
tags:
- '*' # any tag push (e.g., v1.0.0, 0.0.6)
permissions:
contents: write # Required to create GitHub releases and push commits
pull-requests: write # Required to create PRs to opam-repository
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
# This is your current workflow
- uses: ocaml/setup-ocaml@v3
with:
ocaml-compiler: 5.3.0
- run: opam install . --deps-only
- run: opam install dune-release -y
# Add the dune-release-action
- uses: davesnx/dune-release-action@v0.2
with:
packages: 'your-package'
github-token: ${{ secrets.GH_TOKEN }}- uses: davesnx/dune-release-action@v0.2
with:
packages: 'your-package' # (required) The package name(s) to publish to the opam-repository
packages: | # you can pass multiple packages
package-one
package-two
package-three
github-token: ${{ secrets.GH_TOKEN }} # (required) Personal token (classic) with `repo` and `workflow` scopes
changelog: './CHANGES.md' # (optional) Filename to extract PR descriptions and validate tag
verbose: true # Show detailed logs
to-opam-repository: true # Submit PR to opam-repository
to-github-releases: true # Create GitHub release
include-submodules: true # Include git submodules in the tarball| Input | Description | Example |
|---|---|---|
packages |
Package name(s) to release. Single package as string or multiple as array | html_of_jsx or ["pkg1", "pkg2"] |
github-token |
GitHub token for API access | ${{ secrets.GH_TOKEN }} |
Your github-token secret must have these scopes:
- ✅
repo- Full control of private repositories - ✅
workflow- Update GitHub Action workflows (required for opam-repository PRs)
To create or update your token:
- Go to https://github.com/settings/tokens
- Create a new token (classic) or edit existing
- Enable
repoandworkflowscopes - Add it to your repository secrets as
GH_TOKEN
| Input | Description | Default |
|---|---|---|
changelog |
Path to changelog file | ./CHANGES.md |
verbose |
If true, shows detailed logging output | false |
to-opam-repository |
If true, submits a PR to opam-repository | true |
to-github-releases |
If true, creates a GitHub release | true |
include-submodules |
If true, includes git submodules in the distribution tarball | false |
Your CHANGES.md should follow this format:
# Unreleased
(Optional - will trigger a warning if not empty)
## 0.0.6 (2025-10-13)
- Added new feature X
- Fixed bug in Y
- Improved performance of Z
## 0.0.5 (2025-10-01)
- Previous version changes## v1.0.0- With 'v' prefix## 1.0.0- Without prefix## 1.0.0 (2025-10-13)- With date## 1.0.0-beta.1- Pre-release versions
| Output | Description |
|---|---|
version |
Extracted version from git tag |
release-status |
Status of the release (success or failed) |
MIT License - See LICENSE