`once deploy` should be idempotent and support zero-downtime replacement
- Dominant language
- Go
- Stars
- 1.9k
- Forks
- 89
- Avg merge
- 20h 21m
- Merged PRs (30d)
- 16
Description
Currently `once deploy --host ` fails with `ErrHostnameInUse` if the hostname is already in use. This makes the CLI unsuitable for automated workflows (CI/CD pipelines, deployment scripts) where the same command is expected to be re-runnable safely.
The TUI already has the right behaviour: when you change settings for a running app, it performs a zero-downtime replacement — start the new container, wait for kamal-proxy to health-check it and cut over traffic, then remove the old container. The CLI should do the same.
## Proposed behaviour
- If the hostname is not in use: deploy as today (no change).
- If the hostname is already in use by an app with the **same image and settings**: do nothing and exit successfully (idempotent).
- If the hostname is already in use but the **image or settings differ**: perform a zero-downtime replacement using the same `deployWithVolume` → `removeContainersExcept` flow the TUI uses.
## Why this matters
- Running `once deploy` from a CI pipeline on every push is the natural usage pattern, but today it requires a manual `once remove` first.
- The zero-downtime logic already exists in `Application.Deploy()` — the CLI just needs to look up the existing app by hostname instead of failing when it finds one.
- Idempotency also removes the footgun where a failed deploy leaves an app registered under a hostname and blocks all future deploys until manually cleaned up.
## Suggested implementation sketch
In `deploy.go`, instead of calling `ns.HostInUse(host)` and returning an error, look up the existing app by host. If found, reuse its `Application` object (preserving the app name and volume) and call `app.Deploy()` with the updated settings — exactly what `settings.go:handleFormSubmit` does.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in deploy.go and compare its hostname handling with settings.go:handleFormSubmit and Application.Deploy(). Trace the existing deployWithVolume and removeContainersExcept flow, then verify that an unchanged app exits successfully while changed image or settings perform a zero-downtime replacement. Confirm the existing no-conflict deployment path remains unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, go
- Domain
- cli, devops
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100