Reusable GitHub workflows for container builds and verified pull-request previews.
Quick start · Workflows · Preview comments · Contributing
Add .github/workflows/container-main.yml to an application with a root Dockerfile:
name: Build main container
on:
push:
branches: [main]
workflow_dispatch:
jobs:
build:
permissions:
contents: read
packages: write
uses: vahor-labs/actions/.github/workflows/main-build.yml@mainPublishes Linux AMD64 images to ghcr.io/<owner>/<repository> (lowercase).
Uses GITHUB_TOKEN; no deployment secrets needed.
| Workflow | Caller event | Required permissions |
|---|---|---|
| main-build.yml | Push to main or manual dispatch |
contents: read, packages: write |
| pr-build.yml | PR opened, synchronized or reopened | contents: read, packages: write, pull-requests: write |
| image-cleanup.yml | PR closed, schedule or manual dispatch | contents: read, packages: write |
- Main:
sha-<full SHA>. Only the current head can updatemain. - Pull requests:
pr-<number>-<full head SHA>, built from the actual PR head. - Fork PRs: build only. No publishing or PR updates.
Deploy by immutable digest, not the mutable main tag.
Use pull_request, never pull_request_target. Preview URLs are generated under
preview.vahor.fr from the repository name: lowercase, non-alphanumeric runs
replaced with -, trimmed and limited to 46 characters. vahor.fr becomes
vahor-fr, so its caller needs no inputs. Override only when necessary:
with:
preview-prefix: my-appThe prefix must be a lowercase DNS label, at most 46 characters. The generated
URLs are https://<prefix>-pr-<number>.preview.vahor.fr/ and
https://<prefix>-sha-<first 12 head SHA characters>.preview.vahor.fr/.
The action probes the commit URL itself, not an appended endpoint.
Your deployment system must:
- Watch for
preview-readyand deploy the exact PR image. - Route the stable PR hostname to the current preview.
- Restrict the commit-specific route to pods selected by the full head SHA, not merely the 12-character hostname prefix or a shared PR selector. A missing or stale commit must not fall back to another revision, redirect to the stable route, or return an HTTP 200 default backend.
- Retain only the current commit route for each PR; remove the old route when the PR head changes, and remove both routes when the PR closes.
Readiness means HTTP 200 from that isolated commit route, not an application
response containing a SHA. No application code, deployment.json, or PR
APP_BUILD_SHA build argument is required. Full-SHA verification depends on the
infrastructure routing contract above; the action cannot inspect pod selectors.
The main-image workflow still passes APP_BUILD_SHA for the existing production
endpoint.
One bot comment tracks Building → Deploying → Ready. The Building comment and image build run in parallel with separate job permissions; verification waits for both jobs before updating the comment.
Example (placeholder links, commit and timestamp):
| Deployment | Actions | Updated |
|---|---|---|
| ✅ Ready · PR preview · Commit preview | Logs · a1b2c3d |
2026-11-01T12:00:00.000Z |
- Ready: the HTTPS commit-specific URL returns HTTP 200 and the PR head is still current. The comment shows both PR and commit preview links.
- Building / Deploying: retain the stable PR link if already present in the bot comment. The commit link is shown only after readiness succeeds. The stable alias may be briefly unavailable while the single preview pod is replaced.
- Waiting: checks every 5 seconds, for up to 15 minutes, with no-cache requests and a maximum 10-second timeout per probe. Redirects are errors; non-200 responses, network failures and timeouts are retried within the deadline.
- Failed or timed out: no preview link. Rerun to check again.
Keep cleanup triggers in the calling repository:
- PR closed: delete versions used only by that PR.
- Schedule or manual dispatch: delete old, untagged versions.
Set
older_than_hoursto a non-negative integer string (default"24").
Shared versions are preserved. Builds never delete images.
Contribution guide · Report a bug or request a feature
MIT.