# Builds

> How ZopNight turns source code into container images via a GitHub Actions dispatcher — analyze, build, and callback flow.

Source: https://zop.dev/developer-docs/deployments/builds

---

Builds turn source code into container images that [deployments](https://zop.dev/docs/deployments/deployments) can run. ZopNight builds from a connected git [integration](https://zop.dev/docs/integrations) (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.

**Info**

Every endpoint on this page is served by the **deployer** service. The build pipeline is part of the deployer's runtime responsibility, distinct from the catalog rows that live on [config](https://zop.dev/docs/deployments/projects).

**Info**

ZopNight does not expose a separate `/builds` resource. Each deployment [revision](https://zop.dev/docs/deployments/deployments) carries its build state — image ref, status, error message, log tail — and the lifecycle endpoints under `/deployments/{id}/revisions` are how builds are tracked.

## 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

```json title="Response"
{
  "data": [
    {
      "integrationID": "int_github_001",
      "owner": "acme",
      "repo": "checkout",
      "defaultBranch": "main",
      "private": true
    }
  ]
}
```

### GET /branches

List branches in a repository. Pass integrationID + owner + repo for a connected repo, or repoUrl for a public github.com repo. (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](https://github.com/railwayapp/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)

```bash title="Request"
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": "."
  }'
```

```json title="Response"
{
  "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](https://zop.dev/docs/deployments/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)

```json title="Body"
{
  "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](https://zop.dev/docs/deployments/deployments) for revision endpoints, and [Webhooks](https://zop.dev/docs/deployments/webhooks) for how the GitHub push event kicks the build pipeline off in the first place.
