Builds
How ZopNight turns source code into container images via a GitHub Actions dispatcher — analyze, build, and callback flow.
Builds turn source code into container images that deployments can run. ZopNight builds from a connected git integration (GitHub today). The actual docker build runs on a GitHub Actions dispatcher (zop-dev/zopnight-builder) — no in-cluster Kaniko, no shared build farm, no build queue contention between tenants.
Pick a Repository & Branch
Repos and branches are read live through the connected GitHub App token (or PAT for self-hosted) — ZopNight does not cache the user’s repo list across sessions.
/repositories List repositories visible through your connected integrations. Used by the deploy wizard's repo picker. (deployer)
{ "data": [ { "integrationID": "int_github_001", "owner": "acme", "repo": "checkout", "defaultBranch": "main", "private": true } ]}/branches List branches in a selected repository. Pass integrationID + owner + repo as query params. (deployer)
Analyze a Repository
Before kicking off a build, the wizard runs an analyzer that inspects the repo and proposes deployment defaults — language, framework, port, health probe path, and (when present) a Dockerfile. Stack detection is powered by Railpack since #1203, so most repos can be deployed without ever opening a config file.
/analyze Analyze a repo + branch and return suggested deployment defaults. Used by the deploy wizard before the deployment is created. (deployer)
curl -X POST https://zopnight.com/api/analyze \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "integrationID": "int_github_001", "owner": "acme", "repo": "checkout", "branch": "main", "rootPath": "." }'{ "data": { "language": "go", "framework": "gofr", "suggestedPort": 8080, "suggestedHealthPath": "/health", "dockerfile": "Dockerfile", "buildContext": ".", "needsBuild": true, "warnings": [] }}Note: /analyze is the wizard-time analyzer (pre-create). For re-analyzing an existing deployment, see POST /deployments/{id}/analyze on the Deployments page.
How a Build Runs
- You create a deployment (or push to a branch with auto-deploy on). Config writes the catalog row + revision #1 placeholder and enqueues a job on the deployer’s MySQL
jobsqueue. - A deployer worker claims the job, clones the repo, and dispatches a
workflow_dispatchtozop-dev/zopnight-builderwith a callback URL and an HMAC-signed JWT. - The builder workflow runs Railpack (if there’s no Dockerfile) or a plain
docker build, then pushes the image to your registry. - The workflow POSTs the result back to
/build-callbacks/{revisionID}. The deployer verifies the JWT, stamps the image ref onto the revision, and re-enqueues the deploy job. - The deployer mints a per-deploy ephemeral kubeconfig from the cloud account creds and applies a Helm release to the target cluster’s namespace.
Build Callback
The builder workflow reports back over an unauthenticated gateway path that the deployer secures with a body-carried HMAC-signed JWT — the secret is BUILD_CALLBACK_SECRET in the deployer’s environment. If the secret isn’t set, the callback route isn’t registered at all (so the workflow_dispatch path is effectively disabled in environments where you haven’t configured builds).
/build-callbacks/{revisionID} Builder workflow → deployer callback. Auth is the JWT in the JSON body (signed with BUILD_CALLBACK_SECRET), not the gateway session. (deployer)
{ "jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.<payload>.<sig>", "status": "succeeded", "imageRef": "registry.zopnight.com/acme/checkout:sha-abc1234", "logTailUrl": "https://github.com/zop-dev/zopnight-builder/actions/runs/12345"}See Deployments for revision endpoints, and Webhooks for how the GitHub push event kicks the build pipeline off in the first place.