Documentation

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.

GET/repositories

List repositories visible through your connected integrations. Used by the deploy wizard's repo picker. (deployer)

Response · json
{
"data": [
  {
    "integrationID": "int_github_001",
    "owner": "acme",
    "repo": "checkout",
    "defaultBranch": "main",
    "private": true
  }
]
}
GET/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.

POST/analyze

Analyze a repo + branch and return suggested deployment defaults. Used by the deploy wizard before the deployment is created. (deployer)

Request · bash
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": "."
}'
Response · json
{
"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

  1. 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 jobs queue.
  2. A deployer worker claims the job, clones the repo, and dispatches a workflow_dispatch to zop-dev/zopnight-builder with a callback URL and an HMAC-signed JWT.
  3. The builder workflow runs Railpack (if there's no Dockerfile) or a plain docker build, then pushes the image to your registry.
  4. 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.
  5. 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).

POST/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)

Body · json
{
"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.