basecamp / basecamp/once

`once deploy` should be idempotent and support zero-downtime replacement

Open
#47 0 comments 0 reactions 0 assignees View on GitHub
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.