Skip to content

Releases: webcane/docker-deploy

v0.6.0

Choose a tag to compare

@github-actions github-actions released this 23 May 05:02

Changelog

  • afe57ba docs(quick-260523-cos): record commit hash in STATE.md
  • 4aef2ac fix(release): install cosign before goreleaser so artifact signing succeeds

v0.3.0

Choose a tag to compare

@webcane webcane released this 21 May 04:43

Phase 7: v2 Leftovers

Goal: Ship a wave of small v2 quality-of-life improvements: expand the built-in exclude list to cover common dev-tooling directories, add a --skip-env flag so operators can preserve remote secrets across deploys, and add a --verbose flag for detailed deploy output.

Status: Verified ✓ (7/7 observable truths; live SSH end-to-end pending human confirmation)


What's New

--skip-env flag

Operators can now preserve remote secrets across deploys:

docker deploy --host ssh://user@host:22 --skip-env
  • Excludes .env from SFTP upload, leaving the remote copy untouched
  • Configurable via deploy.yaml with skip_env: true
  • CLI flag takes precedence when both are set
  • Additive — appends .env to the effective exclude list without replacing other excludes
  • Prints a visible warning when active: WARNING: .env not uploaded — remote .env left unchanged
  • Remote .env is preserved across atomic swap — backed up to /tmp/docker-deploy-env-<ts> before the swap and restored after

--verbose flag

Detailed deploy output on demand:

docker deploy --host ssh://user@host:22 --verbose
  • Per-file transfer lines ( -> path/to/file)
  • SSH command lines ([ssh] docker compose up -d)
  • Exit code lines ( → exit 0)
  • Preflight checklist lines ( [PASS] docker-compose-v2, [WARN] passwordless-sudo)
  • Without --verbose: output remains terse; a single rollup line appears if any warnings accumulated

Expanded default exclude list

10 new entries added to the built-in exclude list (from 6 → 16 total):

Added Purpose
.claude/ Claude AI context files
.github/ GitHub Actions / workflows
.planning/ GSD planning artifacts
.idea/ JetBrains IDE settings
.vscode/ VS Code settings
*.swp, *.swo Vim swap files
coverage/ Test coverage output
dist/ Build artifacts
.terraform/ Terraform state

These are silently skipped unless the user explicitly re-includes them.

Warning rollup system

Non-verbose mode now accumulates warnings and prints a single summary line at the end:

WARN: there are some warnings during deployment. For more details use --verbose flag

Bug Fixes

  • Remote .env preserved across atomic swap when --skip-env is set — previously the atomic mv would overwrite the remote .env even when skip-env was active; now backs up and restores
  • Warning rollup fires in both verbose and non-verbose mode — fixed a guard bug where the rollup was only shown in verbose mode
  • Dead sshExecVerbose function removed — replaced by the inline [ssh] logging approach
  • Deploy complete status message format — omit colon when using default SSH port (:22 case)

Internal Changes

  • config.FlagOpts struct replaces the 10-positional-arg Resolve() signature — cleaner call sites, easier to extend
  • Upload() and RunCompose() gain verbose bool param propagated from resolved.Verbose
  • buildDeployCmd() extracted from main() for cobra flag registration testability
  • All packages: 100% passing unit tests (33 commits, 6 testable packages)

Requirements Addressed

Req Description
FILES-02 Default exclude list: .git/, node_modules/, vendor/, *.log, .DS_Store, __pycache__/ (+ 10 new entries)

Full Changelog

v0.2.0...v0.3.0

v0.2.0

Choose a tag to compare

@webcane webcane released this 19 May 14:17

Summary

Phase 4: Core Deploy Loop
Goal: A developer can deploy a local compose project to a remote VPS with a single command and see compose output streamed to their terminal.
Status: Verified ✓

This release wires together file copy (Phase 3) and compose execution into a single docker deploy command. Deploy to any SSH-accessible VPS — no git on the remote required. Output is streamed line-by-line; the plugin exits non-zero on any failure.


Changes

Plan 01: Config ComposeFile Resolution

Config package extended with three-tier compose file selection: --compose-file flag → deploy.yaml → auto-detect (compose.yaml then docker-compose.yml).

Key files: internal/config/config.go, internal/config/config_test.go

Plan 02: RunCompose SSH Execution

New internal/compose package with RunCompose(). Executes docker compose -f <path> up -d --remove-orphans on the remote host. PTY detection routes output: allocated xterm-256color PTY when running in a terminal; two goroutines drain stdout/stderr in CI/piped mode.

Key files: internal/compose/run.go, internal/compose/run_test.go

Plan 03: Integration & Wiring

Full deploy loop wired into main.go: --compose-file flag, basename injection guard, Upload() then RunCompose(). Verified end-to-end against a real SSH host across 6 scenarios including compose validation errors and non-zero exit code propagation.

Key files: cmd/docker-deploy/main.go

Plan 04: Auth Fallback Sequence

Structured three-stage auth fallback in Upload(): direct copy → passwordless sudo (sudo -n) → interactive password prompt (3 retry attempts). Password collected once and reused across all privileged operations (mkdir, mv, rm). Previously, deployments to /opt or other root-owned directories would fail; now they proceed via sudo with clear per-stage warnings.

Key files: internal/filetransfer/upload.go, internal/filetransfer/upload_test.go, cmd/docker-deploy/main.go


Requirements Addressed

  • DEPLOY-01docker deploy --host ssh://user@host completes the full copy-then-compose cycle without additional flags
  • DEPLOY-04docker compose up -d --remove-orphans executes on the remote host after files are copied
  • DEPLOY-05 — Plugin exits non-zero if file copy fails, compose fails, or SSH connectivity is lost mid-deploy
  • DEPLOY-06 — Compose output is streamed line-by-line to the local terminal (PTY or piped)
  • DEPLOY-07 — Auth fallback sequence: direct copy → passwordless sudo → interactive password prompt

Verification

  • Automated: 53 tests pass, 5 skipped (interactive password tests — stdin mocking deferred), 0 failures
  • go build ./... and go vet ./... clean
  • Human UAT: 6 end-to-end scenarios verified against real SSH host (192.168.1.99)
  • No InsecureIgnoreHostKey in production code
  • No TBD/FIXME/XXX debt markers in production code

Key Decisions

  • RunCompose() uses session.Start() not session.Run() — allows wg.Wait() before session.Wait() to ensure pipe drain before exit status check
  • Basename validation (filepath.Base(composeFile) == composeFile) placed in runDeploy() at the trust boundary, not inside RunCompose()
  • context.Background() passed to RunCompose — compose up -d is detached and returns quickly; no separate deadline needed
  • Password collected once via golang.org/x/term.ReadPassword and reused across all sudo operations in a single deploy
  • Staging in /tmp/docker-deploy-<ts> avoids /opt permission issues; target dir creation is a separate step with sudo fallback

Quick Fixes (also in this release)

Fix Commit Description
260519-c216 833cf07 Eliminate hanging goroutines in RunCompose tests — refactor mock SSH server, fix defer ordering
260519-oax 40dc518 Deduplicate "passwordless sudo not configured" warning — show once by default
260519-q02 703d819 Fix health check docker inspect exit status 1 for containers with no HEALTHCHECK directive