Every Go-implemented plugin's `:report --format json` now emits keys without the redundant `<plugin>-` head segment, matching the shape bash plugins have always emitted. The CLI flag names and `:set` semantics are unchanged. For backwards compatibility during the 0.38.x patch series, the legacy `<plugin>-<property>` keys are emitted side-by-side with the new keys, and a future major release will drop the legacy keys. `common.ReportSingleApp` is refactored to accept a `ReportSingleAppInput` struct with a `Validate()` method so the input is checked before any work runs, which also catches the latent `"docker options"` reportType bug at the API boundary.
198 lines
7.8 KiB
Markdown
198 lines
7.8 KiB
Markdown
# Build Tracking
|
|
|
|
> [!IMPORTANT]
|
|
> New as of 0.38.0
|
|
|
|
Every deploy that flows through Dokku - whether triggered by `git push`, `ps:rebuild`, `ps:restart`, `config:set`, or `git:from-archive` / `git:from-image` / `git:sync` / `git:load-image` - is recorded as a structured build record on disk. The `builds` plugin lets operators inspect what is currently deploying, look up the result of an old deploy, and stream the captured build log without depending on `journalctl`.
|
|
|
|
```
|
|
builds:cancel <app> # Cancel a running build for an app
|
|
builds:info <app> <build-id> [--format json] # Show details for a single build
|
|
builds:list [<app>] [--format json] [--kind ...] [--status ...]
|
|
# List builds (running across all apps, or running + history for one)
|
|
builds:output <app> [<build-id>|current] # Show build output (tail for live, cat for finished)
|
|
builds:prune <app> [--all-apps] # Reap abandoned records and apply retention
|
|
builds:report [<app>] [<flag>] # Display a build report
|
|
builds:set [--global|<app>] <key> [<value>] # Set or clear a builds property
|
|
```
|
|
|
|
## Build records
|
|
|
|
Every build is identified by a sortable base36 ULID-style id (`DOKKU_BUILD_ID`) generated at deploy start. For each build, Dokku writes:
|
|
|
|
- `$DOKKU_LIB_ROOT/data/builds/<app>/<build-id>.json` - the structured record
|
|
- `$DOKKU_LIB_ROOT/data/builds/<app>/<build-id>.log` - the captured stdout/stderr of the deploy
|
|
|
|
Output is also tagged into syslog as `dokku-<build-id>` so `journalctl -t dokku-<build-id>` continues to work. The on-disk log file is the durable source of truth and is read for `builds:output` even when journald has rotated old entries away.
|
|
|
|
### Record schema
|
|
|
|
```json
|
|
{
|
|
"id": "01j8c4xv7bk5w3",
|
|
"app": "myapp",
|
|
"kind": "build",
|
|
"pid": 12345,
|
|
"started_at": "2026-04-30T13:50:00Z",
|
|
"finished_at": "2026-04-30T13:51:14Z",
|
|
"status": "succeeded",
|
|
"source": "git-hook",
|
|
"exit_code": 0
|
|
}
|
|
```
|
|
|
|
- **kind** - `build` for paths that produce a new image (`git push`, `git:*`, `ps:rebuild`); `deploy` for paths that re-deploy an existing image (`ps:restart`, `ps:start`, `dokku deploy`, `config:set`).
|
|
- **status** - on-disk values are `running | succeeded | failed | canceled`. `abandoned` is a fifth display-only value computed at read time for `running` records whose PID is no longer alive; it is never persisted to the record.
|
|
- **source** - the user-typed command that originated the deploy (e.g. `git-hook`, `ps:restart`, `config-redeploy`, `git:sync`).
|
|
|
|
## Listing builds
|
|
|
|
Without an app argument, `builds:list` shows currently-running builds across every app on the host:
|
|
|
|
```shell
|
|
dokku builds:list
|
|
```
|
|
|
|
```
|
|
=====> Currently running builds
|
|
App Build ID Kind PID Source Started
|
|
myapp 01j8c4xv7bk5w3 build 12345 git-hook 2026-04-30T13:50:00Z
|
|
```
|
|
|
|
With an app, `builds:list` returns running builds plus the most recent finalized records up to the configured retention:
|
|
|
|
```shell
|
|
dokku builds:list myapp
|
|
```
|
|
|
|
Filter by kind or status:
|
|
|
|
```shell
|
|
dokku builds:list myapp --kind build
|
|
dokku builds:list myapp --status running
|
|
dokku builds:list --format json
|
|
```
|
|
|
|
## Inspecting a single build
|
|
|
|
```shell
|
|
dokku builds:info myapp 01j8c4xv7bk5w3
|
|
```
|
|
|
|
```
|
|
=====> Build 01j8c4xv7bk5w3
|
|
Build ID: 01j8c4xv7bk5w3
|
|
App: myapp
|
|
Kind: build
|
|
Status: succeeded
|
|
PID: 12345
|
|
Source: git-hook
|
|
Started: 2026-04-30T13:50:00Z
|
|
Finished: 2026-04-30T13:51:14Z
|
|
Duration: 1m14s
|
|
Exit Code: 0
|
|
Log: /var/lib/dokku/data/builds/myapp/01j8c4xv7bk5w3.log
|
|
```
|
|
|
|
JSON output includes the same fields plus a computed `log_path`:
|
|
|
|
```shell
|
|
dokku builds:info myapp 01j8c4xv7bk5w3 --format json | jq .
|
|
```
|
|
|
|
## Streaming build output
|
|
|
|
```shell
|
|
# tail -f the live build, or cat the log for a finished one
|
|
dokku builds:output myapp 01j8c4xv7bk5w3
|
|
|
|
# resolve "current" from the in-flight deploy
|
|
dokku builds:output myapp current
|
|
```
|
|
|
|
If the on-disk log file is missing (for example, a build from before this plugin was installed), `builds:output` falls back to `journalctl -t dokku-<build-id>`.
|
|
|
|
## Cancelling a build
|
|
|
|
`builds:cancel` reads the active `.deploy.lock` for an app, looks up the matching build record, and sends `SIGQUIT` to the deploy's process group. The record is finalized as `canceled` (or `failed` if the process had already exited without finalizing - in that case Dokku marks the record so it doesn't sit in `running` forever).
|
|
|
|
```shell
|
|
dokku builds:cancel myapp
|
|
```
|
|
|
|
If the record is already finalized when cancel runs, no signal is sent and the record is left untouched.
|
|
|
|
## Retention
|
|
|
|
Build records are pruned by count, not by age. The default retention is **20** records per app. Live in-flight deploys are never pruned regardless of count.
|
|
|
|
Set a per-app retention:
|
|
|
|
```shell
|
|
dokku builds:set myapp retention 50
|
|
```
|
|
|
|
Set the global default:
|
|
|
|
```shell
|
|
dokku builds:set --global retention 10
|
|
```
|
|
|
|
Clear an override (falls back to the global value, then the default):
|
|
|
|
```shell
|
|
dokku builds:set myapp retention
|
|
```
|
|
|
|
## Manual pruning
|
|
|
|
`builds:prune` invokes the same logic that runs at the end of every deploy - it reaps abandoned records (status=running with a dead PID, finalized as `failed`) and trims the directory to the configured retention. Useful after lowering retention via `builds:set` or to clean up after a host reboot:
|
|
|
|
```shell
|
|
dokku builds:prune myapp
|
|
dokku builds:prune --all-apps
|
|
```
|
|
|
|
## Reports
|
|
|
|
```shell
|
|
dokku builds:report
|
|
dokku builds:report myapp
|
|
dokku builds:report myapp --build-status
|
|
```
|
|
|
|
Available flags:
|
|
|
|
- `--build-id`, `--build-kind`, `--build-status`, `--build-pid`, `--build-source`, `--build-started-at`, `--build-finished-at`, `--build-exit-code`: details of the most recent build for the app
|
|
- `--builds-retention`: per-app retention override (empty if none)
|
|
- `--builds-global-retention`: global retention override (empty if none)
|
|
- `--builds-computed-retention`: the resolved retention applied to this app
|
|
|
|
`--build-status` returns the **display** status, so an abandoned in-flight build shows `abandoned` rather than `running`. The raw on-disk status is only visible by reading the JSON record directly.
|
|
|
|
## Properties
|
|
|
|
### Settable properties
|
|
|
|
> [!NOTE]
|
|
> The `Report flags` column lists the CLI argument names accepted by `builds:report`. The JSON keys emitted by `builds:report --format json` are the same names with the leading `--builds-` stripped (e.g. `retention`, `global-retention`, `computed-retention`). Legacy keys with the `builds-` prefix (e.g. `builds-retention`) are also emitted during the 0.38.x deprecation window and will be removed in a future major release. Status keys (`build-id`, `build-status`, etc.) have no plugin prefix and are unaffected.
|
|
|
|
| Property | Scope | Default | Report flags | Description |
|
|
|---|---|---|---|---|
|
|
| `retention` | app + global | `20` | `--builds-retention`, `--builds-global-retention`, `--builds-computed-retention` | Number of recent build records kept per app; older finalized records are pruned at the end of each deploy |
|
|
|
|
### Read-only flags
|
|
|
|
The following flags surface in `builds:report` but are not managed by `builds:set` - they are derived metadata recorded during the build:
|
|
|
|
| Flag | Description |
|
|
|---|---|
|
|
| `--build-id` | Unique identifier of the most recent build for the app |
|
|
| `--build-kind` | Whether the record was a `build` or a `deploy` |
|
|
| `--build-status` | Display status (`running`, `succeeded`, `failed`, `canceled`, `abandoned`); computed at read time |
|
|
| `--build-source` | Trigger that started the build (e.g. `git-hook`, `ps:rebuild`, `ps:restart`) |
|
|
| `--build-pid` | PID of the build process |
|
|
| `--build-started-at` | UNIX timestamp the build started |
|
|
| `--build-finished-at` | UNIX timestamp the build finished |
|
|
| `--build-exit-code` | Exit code of the build process |
|