Reproducible builds of the third-party solvers and dependencies that ship with MiniZinc (CBC, HiGHS, OR-Tools CP-SAT, Gecode, Gecode+Gist, Chuffed), for every supported platform.
Unlike the previous GitLab setup — where solver versions floated and downstream projects consumed "latest" — every version here is explicitly pinned in a single manifest, each build is published individually as a release asset, and upstream updates arrive as Dependabot-style pull requests.
Each (dependency, platform) build is published as one asset on a per-dependency
GitHub Release tagged <dep>-<version>:
Release gecode-eebbc1bfaef1decd3ab6a3c583c7b55f5fe29600
asset gecode-eebbc1b…-x86_64-linux-gnu.tar.gz
asset gecode-eebbc1b…-aarch64-linux-gnu.tar.gz
asset gecode-eebbc1b…-aarch64-apple-darwin.tar.gz
...
There is no compose/bundle step and no separate artifact registry: the release is the artifact, and "already built?" is simply "does that asset exist?". So bumping one dependency rebuilds only that dependency (its new-version assets are missing); every other dependency's assets already exist and are skipped. Old versions stay published, so any pinned build can be re-downloaded without rebuilding.
Consumers (e.g. libminizinc) keep a per-dependency lock file and download each dependency's asset for their system triple individually.
dependencies.toml— the single source of truth: pins every solver version/commit and every toolchain version (coinbrew, Bazel, bazelisk, rules_pkg, OpenSSL, Qt), plus each platform's runner, (digest-pinnable) base image, system triple, and asetupcommand that installs build deps at job time.- Base images are common public ones —
manylinux_2_28(glibc 2.28, low floor) for glibc-linux,alpinefor musl,emscripten/emsdkfor wasm — with deps installed on the runner via the platformsetup(no bespoke build image). Qt forgecode_gistis fetched on demand:aqtinstallinside the linux container, andinstall-qt-actionon the native osx/win64 runners. recipes/*.sh— build one dependency each; versions come from the environment (injected from the manifest), never hard-coded.scripts/manifest.py— expands the(dependency × platform)matrix, computes each cell's release tag / asset name / recipe env, and emits the resolved lockfile.scripts/update_check.py— the update bot: resolves the newest upstream version of each tracked entry and rewrites a single pin.
| Workflow | Trigger | Does |
|---|---|---|
build.yml |
reusable / dispatch | matrix build; build + (optionally) publish each missing asset |
publish.yml |
push to main / dispatch |
build & publish all missing assets, then open per-dep bump PRs in libminizinc |
update-bot.yml |
weekly / dispatch | one PR per outdated dependency (bumps this manifest) |
pr-validate.yml |
PR touching manifest/recipes/resources | build only the changed dependencies (no publish) |
x86_64-linux-gnu, aarch64-linux-gnu, x86_64-linux-musl, aarch64-linux-musl,
aarch64-apple-darwin, x86_64-windows, wasm32-emscripten.
- Pin base images by digest. Replace the
# TODO: pin @sha256:...tags on the[platforms.*].containerentries independencies.toml. - Fill bazelisk
sha256for each asset in[toolchain.bazelisk.sha256]. - GitHub App for bump PRs. Register one GitHub App in the org (Contents +
Pull requests: read/write), installed on
minizinc-vendorandlibminizinc, and store its App ID / private key as org secretsMINIZINC_BOT_APP_IDandMINIZINC_BOT_APP_KEY.update-bot.ymlandpublish.ymlmint short-lived tokens from it so their bump PRs trigger CI (GITHUB_TOKEN-created PRs don't, and it can't write cross-repo). Publishing this repo's own releases uses the built-inGITHUB_TOKEN. - Self-hosted runners (optional). Everything starts on GitHub-hosted runners.
If
or-tools:win64(Bazel + MSVC) exhausts the hosted disk/time, point that platform'srunnerin the manifest at a self-hosted label — no workflow edit needed.
pip install tomli # only needed on Python < 3.11
python3 scripts/manifest.py versions # dep -> pinned version
python3 scripts/manifest.py release-tag --dep gecode
python3 scripts/manifest.py asset --dep cbc --platform win64
python3 scripts/manifest.py matrix | python3 -m json.tool
python3 scripts/update_check.py check # what's outdated upstream
python3 scripts/manifest.py lock # resolved lockfile