Release Versioning¶
How soa images are versioned, tagged, and auto-deployed to staging.
Tag scheme¶
Every successful master push that follows the conventional commit format produces one GH release and three DOCR image tags:
| Tag | Example | Purpose |
|---|---|---|
v<semver> |
v1.3.0 |
Primary deploy tag. Used by do-deploy.yml. |
<short-sha> |
abc1234 |
Traceability. Points to exact commit. |
latest |
latest |
Convenience. Always newest master build. |
workflow_dispatch rebuilds (using the ref input) push only <short-sha> - no semver, no latest.
Bump rules¶
Conventional commit messages since the last semver tag determine the bump:
| Commit prefix | Bump | Example |
|---|---|---|
feat: / feat(<scope>): |
minor | v1.2.0 -> v1.3.0 |
BREAKING CHANGE in body, or ! in type |
major | v1.2.0 -> v2.0.0 |
Everything else (fix:, chore:, ci:, etc.) |
patch | v1.2.0 -> v1.2.1 |
Policy: every master push with a conventional commit type produces a release. Commits without a recognized type prefix (e.g. bare "Initial commit") do not trigger a release - they push a <short-sha> image only, with no version bump.
Baseline¶
First release uses v1.0.0. No existing semver tags existed before BD-5.2 was implemented.
How it works inside do-build.yml¶
push master
-> validate-jsonnet
-> version job (semantic-release dry_run=true: compute v<semver>, no tag yet)
-> bake (build image tagged v<semver>)
-> lint + test + trivy
-> push (push v<semver> + short-sha + latest to DOCR)
-> sentry (create Sentry release named v<semver>)
-> release (semantic-release real run: create git tag + GH release,
then dispatch do-deploy oep-stg)
-> prune (keep newest 30 DOCR tags by count)
The release job runs after push succeeds. semantic-release dry-run in the version job computes the next version without creating the tag - the real tag + GH release is only created once the image is confirmed pushed. This guarantees no orphaned git tags for failed builds.
Versioning is driven by .releaserc.json at the soa repo root using cycjimmy/semantic-release-action@v4.
oep-stg auto-deploy¶
After creating the GH release, the release job automatically dispatches do-deploy.yml for oep-stg:
oep-stg has no approval gate - it deploys immediately.
Prod tenants (mansety-prd, us-prd) are never auto-deployed. Operator must dispatch manually and the Backend team approval gate fires before proceed.
See Promote Image for manual deploy steps.
Dispatch rebuild (no semver)¶
Rebuilding an old commit via workflow_dispatch (using the ref input) does NOT produce a new semver or GH release. It pushes only <short-sha> to DOCR. This is intentional - rebuilds are for recovering a specific commit's image, not releasing new code.
# Rebuild image from a specific commit or tag
gh workflow run do-build.yml -R unipuka/soa -f ref=abc1234
# or
gh workflow run do-build.yml -R unipuka/soa -f ref=v1.2.3
Bugsnag release integration¶
PHP has no sourcemaps; Bugsnag "release" = a build report sent to build.bugsnag.com.
This is posted per-tenant per-deploy from do-deploy.yml (after the Sentry deploy marker step).
Canonical version: full commit SHA¶
Both Sentry and Bugsnag use the full COMMIT_SHA baked into the image at build time as the
canonical version identifier. This ensures errors in Sentry and Bugsnag both point to the
same image + commit.
| Layer | Value |
|---|---|
Runtime (config/sentry.php) |
COMMIT_SHA env (full SHA) |
Runtime (config/bugsnag.php) |
BUGSNAG_APP_VERSION falling back to COMMIT_SHA |
Sentry CI (do-build.yml) |
v{semver} or 7-char SHA |
Bugsnag CI (do-deploy.yml) |
Full SHA resolved from deploy tag |
Per-tenant project keys¶
Each tenant has a separate Bugsnag project. The BUGSNAG_API_KEY secret is scoped to
each GitHub Environment (oep-stg, mansety-prd, us-prd) so do-deploy.yml picks up
the correct key automatically.
| Tenant | Bugsnag API key | GH Environment |
|---|---|---|
| oep-stg | see Doppler oep/oep-stg → BUGSNAG_API_KEY |
oep-stg |
| mansety-prd | see Doppler oep/mansety-prd → BUGSNAG_API_KEY |
mansety-prd |
| us-prd | see Doppler oep/us-prd → BUGSNAG_API_KEY |
us-prd |
Release stage mapping¶
do-deploy.yml maps tenant -> releaseStage for the build report:
| Tenant | Release stage |
|---|---|
oep-stg |
staging |
mansety-prd, us-prd |
production |
This must match config/bugsnag.php release_stage (defaults to APP_ENV).
V&V¶
- Trigger a deploy:
gh workflow run do-deploy.yml -R unipuka/soa -f tag=v1.0.2 -f tenant=oep-stg - Bugsnag dashboard -> Releases -> filter by stage
staging-> release with appVersion = full SHA appears - Trigger a deliberate exception on oep-stg only (staging;
tinkermay be unavailable on production images):kubectl -n oep-stg exec deploy/oep-stg-laravel-api -- php artisan tinker --execute="throw new \Exception('smoke-test');"-> Bugsnag captures the error with the correct appVersion (matching the deployed build's SHA). For production tenants, use a dedicated/smoke-errortest route if available, or verify via a naturally occurring exception rather than triggering one.
Checking releases¶
# List recent GH releases
gh release list -R unipuka/soa -L 10
# List DOCR tags for the api repo
doctl registry repository list-tags api
# Show what tag is deployed per tenant
cat apps/laravel/values-oep-stg.yaml | grep 'image.tag\|tag:'
cat apps/laravel/values-mansety-prd.yaml | grep 'image.tag\|tag:'