feat(deploy): source deploys against a local daemon — 501 falls back to docker build

Merged
FE
3mo ago
+96-8

Why

insta deploy <dir> was cloud-only: it mints a Fly deploy token, which insta-oss answers with a 501, and the command dead-ended — breaking the parity rule that one deploy script runs unchanged on both targets (insta-oss roadmap Phase 4).

What

  • On a 501 from the token mint (only a local daemon answers that), the CLI builds the directory locally — docker build -t insta-src-<proj8>-<group>:<timestamp> . — and hands the daemon the tag. The daemon deploys from the same docker this shell uses, so no registry, no push, no flyctl.
  • ensureFlyctl() moved after the token mint: the local path never auto-installs a third-party CLI it doesn't need.
  • Cloud behavior byte-for-byte unchanged; any non-501 token error still surfaces loudly. Dockerfile EXPOSE port defaulting applies to both paths as before.
  • buildFromSource exported with the repo's injectable-runner pattern (no global mocks).

Verification

  • 371/371 tests (4 new: tag shape, docker invocation + failure surfacing, the 501 fallback path, non-501 re-throw), typecheck clean.
  • Live end-to-end: insta deploy . against a real instad — CLI fell back, built nginx:alpine-based source locally, daemon served the source-built content at localhost:80.

🤖 Generated with Claude Code


Summary by cubic

Enables source deploys to a local daemon by falling back to a local Docker build when POST /projects/:id/deploy-token returns 501, restoring one-script parity across cloud and OSS. Cloud behavior is unchanged; only the 501 path differs.

  • On 501, build the source dir with docker build -t insta-src-<proj8>-<group>:<timestamp> . and pass the tag to the daemon; uses the host Docker only (no registry, no push, no flyctl).
  • Move ensureFlyctl() after the token mint so the local path never installs flyctl.
  • Export buildFromSource, dockerBuildLocal, and localImageTag; builds accept an injectable BuildRunner (matches repo DI pattern).
  • Preserve error/port behavior: non-501 token errors propagate; Dockerfile EXPOSE defaulting unchanged.
  • Tests added for tag shape, docker invocation and failure surfacing, the 501 fallback path, and non-501 rethrow; e2e validated against a local daemon.