Skip to main content

GitHub Release Process

OIBus releases are automated end-to-end by GitHub Actions: contributors only land Conventional-Commits PRs, and the rest — version bumping, changelog, multi-platform binaries, Docker images, documentation deployment — runs from a single push to the stable branch.

This page explains the moving parts so you can either trace a release that's in flight, prepare a pre-release for testing, or update the pipeline itself.

Releases are maintained by the Optimistik team

Official releases of OIBus — both stable and pre-release — are cut only by the Optimistik team, on the OptimistikSAS/OIBus repository. The team owns the release schedule, the signing keys, and the publishing channels (GitHub Releases, ghcr.io, the documentation site). External contributors don't trigger releases directly: your change ships when the maintainers next promote main to stable. This page is reference material — for understanding what happens after your PR lands, or for maintainers operating the pipeline.

Branching model

BranchPurpose
mainDay-to-day work — every PR squash-merges here. Always green; never released directly.
stableRelease branch — receives main periodically, triggers the release workflow on push.

A release is initiated by fast-forwarding stable to main (typically via a PR from main). No other manual step is required — the rest happens via Actions.

The pipeline at a glance

◇ PR squash-merged to main ← daily contributions (Conventional Commits)

◇ main fast-forwarded to stable ← release trigger (manual)


.github/workflows/new_release.yml (on: push → stable)
└── googleapis/release-please-action
├─ Opens a "release PR" against stable
│ (bumps every package.json + lockfile + openapi.json + Dockerfile
│ + docker.mdx, regenerates the CHANGELOG)
└─ When that PR is merged → tags + publishes a GitHub Release


.github/workflows/build.yml (on: release published — or manual workflow_dispatch)
├── prepare → resolve release info + generate the SBOM (once)
├── build (5-platform matrix) → build · sign (Windows) · package · upload to the release
├── snyk → monitor the SBOM (stable only)
├── docker → build & push the multi-arch image to ghcr.io
├── deploy-documentation → build & publish the documentation site (stable only)
└── slack → notification → #oibus-ci

All files referenced live under .github/:

📦 release-please

release-please is the only thing that ever changes the version number. It reads commits since the last tag, decides the bump, and writes the changes into a PR for the maintainers to review.

Version-bump rules

Driven entirely by commit type — same as Conventional Commits:

Commit typeVersion bumpExample
fix:Patch — 0.0.xfix(cache): correct chunk write
feat:Minor — 0.x.0feat(north): add SFTP retry
feat!: or footer BREAKING CHANGE:Major — x.0.0feat(north)!: replace handleValues

Other types (docs, chore, refactor, perf, test, style, build, ci) do not bump the version — they're recorded in the changelog under the relevant section without causing a release.

What release-please rewrites

When a release PR lands, release-please updates the version field in:

FileField / how
backend/package.jsonversion
backend/package-lock.jsonversion + packages[""].version
frontend/package.jsonversion
frontend/package-lock.jsonversion + packages[""].version
launcher/package.jsonversion
launcher/package-lock.jsonversion + packages[""].version
documentation/package.jsonversion
documentation/package-lock.jsonversion + packages[""].version
documentation/docs/api/openapi.json$.info.version
build/docker/Dockerfileversion string (generic replacer)
documentation/docs/developer/docker.mdxversion string (generic replacer)
CHANGELOG.mdnew entry prepended

The JSON files are updated by jsonpath; the Dockerfile and docker.mdx use release-please's generic replacer (it rewrites the version on lines annotated with an x-release-please-version marker). The exact rules are in release-please-config.json under extra-files — if you add a new package or another file that should track the release version, extend that list.

🛠 What the release workflow actually produces

build.yml runs on release: types: [published] — i.e. only after release-please's release PR has been merged and the GitHub Release object is created. (It can also be triggered manually via workflow_dispatch, optionally with a tag input, to rebuild a specific release.) It is a single workflow of cooperating jobs:

prepare

Runs once. Resolves the release info (tag_name, release_name, whether it's a prerelease) and generates the SBOM once (cdxgenoibus-sbom.json), uploading it as a workflow artifact and — for non-prereleases only — attaching it to the GitHub Release. The matrix builds download this single artifact rather than each regenerating it.

build (5-platform matrix, needs: prepare)

Friendly nameOS runnerPlatform target
macOS arm64macos-15macos-arm64
macOS x64macos-15-intelmacos-x64
Windows x64windows-2025win-x64
Linux x64ubuntu-24.04linux-x64
Linux arm64ubuntu-24.04-armlinux-arm64

Each matrix row (fail-fast: false, so one platform failing doesn't cancel the others):

  1. Builds the frontend, the launcher, and the backend for its platform.
  2. Signs the Windows binaries (oibus.exe, oibus-launcher.exe) via Google Cloud KMS + Sectigo timestamping (runs only on the Windows row).
  3. Sanity-checks the runtime by invoking oibus-launcher --version true.
  4. Bundles the SBOM from prepare into the package, then packages a zip (oibus-<platform>-<tag>.zip) and uploads it to the GitHub Release.
  5. Windows only: builds the Inno Setup installer (oibus-win_x64-setup-<tag>.exe) and uploads it.

snyk, docker, deploy-documentation, slack (needs: build)

JobRuns whenWhat it does
snykstable onlyMonitors the SBOM with Snyk (snyk monitor, target reference OIBus-<tag>).
dockeralwaysBuilds & pushes the multi-arch image (linux/amd64,linux/arm64) to ghcr.io/optimistiksas/oibus.
deploy-documentationstable onlyBuilds the Docusaurus site and publishes it to GitHub Pages (needs: [build, docker]).
slackalways (always())Notifies #oibus-ci with the docker job result (needs: [snyk, docker, deploy-documentation]).

The Docker image tags depend on the release kind:

  • Stable releases get the latest tag and the version tag.
  • Pre-releases get the beta tag and the version tag.

🆕 Creating a pre-release

Pre-releases are useful when you need to publish artefacts for testing before cutting a stable release — typically reserved for the maintainers (operators of OptimistikSAS/OIBus).

A pre-release runs the same build.yml matrix but skips the Snyk monitoring, the SBOM release-asset upload and the documentation deployment, and the Docker image gets the beta tag instead of latest. (The SBOM is still generated in prepare and bundled inside each zip — only the separate release-asset upload is skipped.)

Steps

  1. On GitHub → Releases, click Draft a new release.

    Draft a GitHub release
  2. Fill in the form:

    • Tag: vX.Y.Z-<suffix>.N (semver pre-release suffix — alpha.1, beta.1, rc.1).
    • Target: the branch or commit you want to build from (usually main).
    • Title: vX.Y.Z-<suffix>.N (Pre-release).
    • Description: what changed since the last (pre-)release, known issues, and testing instructions for the people who will pick it up.
    • Set as a pre-release: ✅ check it.
    • Set as the latest release: ❌ leave it unchecked — pre-releases must not become the default download.
  3. Click Publish release. The publish event fires build.yml; binaries and the beta-tagged Docker image will be available a few minutes later, alongside a Slack notification.

Pre-release naming

Stick to the standard semver suffixes (-alpha, -beta, -rc) and a numeric counter. They sort correctly against future stable releases (v3.8.0-rc.1 < v3.8.0) and the Docker beta tag picks them up automatically.

Troubleshooting

SymptomWhat to check
No release PR appears after pushing to stablerelease-please only opens a PR when there are bumping commits since the last tag. chore: / docs: alone don't bump.
Release PR opened but with the wrong versionInspect the commit subjects — a feat!: anywhere drives a major bump. Edit release-please-manifest.json if you need to correct the next version manually.
build.yml doesn't fireConfirm a GitHub Release object was actually created (not just a tag). build.yml listens on release: types: [published] (or run it manually via workflow_dispatch).
Windows binaries unsignedThe KMS auth step needs the GCP_SERVICE_ACCOUNT_JSON and CERT secrets configured for the running repository / fork — these aren't available on contributor forks.
Docker image not tagged latestThe release was marked as pre-release. Stable releases get latest; pre-releases get beta. See the docker job in build.yml.
Documentation site didn't updateThe deploy-documentation job (in build.yml) runs only for non-prereleases and needs: [build, docker] — confirm the release wasn't a pre-release and that the build + docker jobs succeeded.
A single platform failed but others shippedExpected — the build matrix is fail-fast: false. Re-run just the failed job, or re-run build.yml for the tag via workflow_dispatch.
Running on a fork

The release workflow needs REPO_ACCESS_TOKEN, GCP_SERVICE_ACCOUNT_JSON, CERT, SNYK_TOKEN, and SLACK_BOT_TOKEN secrets. Forks won't have those by default; the workflow will skip the parts it can't authenticate, but you'll get an incomplete artefact set. The pipeline is designed to be run from OptimistikSAS/OIBus itself.