summaryrefslogtreecommitdiffstats
path: root/cmd/ship/deploy.go
diff options
context:
space:
mode:
authorbndw <ben@bdw.to>2026-02-08 12:32:59 -0800
committerbndw <ben@bdw.to>2026-02-08 12:32:59 -0800
commita8ad8e934d15d2bf84f942414a89af1d2691adbc (patch)
tree82e6765c9d35968b27ac7ee17f5c201a421dc1d3 /cmd/ship/deploy.go
parentaf109c04a3edd4dcd4e7b16242052442fb4a3b24 (diff)
Add git-centric deployment with Docker builds and vanity imports
New deployment model where projects start with a git remote on the VPS. Pushing to the remote triggers automatic docker build and deploy via post-receive hooks. The base domain serves Go vanity imports and git HTTPS cloning via Caddy + fcgiwrap. - Add `ship init <name>` command to create bare repos and .ship/ config - Add `ship deploy <name>` command for manual rebuilds - Extend `ship host init --base-domain` to set up Docker, git user, fcgiwrap, sudoers, and vanity import infrastructure - Add git-app and git-static types alongside existing app and static - Update remove, status, logs, restart, list, and config-update to handle new types
Diffstat (limited to 'cmd/ship/deploy.go')
-rw-r--r--cmd/ship/deploy.go56
1 files changed, 30 insertions, 26 deletions
diff --git a/cmd/ship/deploy.go b/cmd/ship/deploy.go
index 24eed1e..9ac754c 100644
--- a/cmd/ship/deploy.go
+++ b/cmd/ship/deploy.go
@@ -415,7 +415,7 @@ func updateAppConfig(st *state.State, opts DeployOptions) error {
415 return fmt.Errorf("app %s not found (use --binary to deploy a new app)", opts.Name) 415 return fmt.Errorf("app %s not found (use --binary to deploy a new app)", opts.Name)
416 } 416 }
417 417
418 if existingApp.Type != "app" { 418 if existingApp.Type != "app" && existingApp.Type != "git-app" {
419 return fmt.Errorf("%s is a static site, not an app", opts.Name) 419 return fmt.Errorf("%s is a static site, not an app", opts.Name)
420 } 420 }
421 421
@@ -441,33 +441,37 @@ func updateAppConfig(st *state.State, opts DeployOptions) error {
441 return fmt.Errorf("error creating env file: %w", err) 441 return fmt.Errorf("error creating env file: %w", err)
442 } 442 }
443 443
444 // Regenerate systemd unit 444 // For git-app, the systemd unit comes from .ship/service in the repo,
445 fmt.Println("-> Updating systemd service...") 445 // so we only update the env file and restart.
446 workDir := fmt.Sprintf("/var/lib/%s", opts.Name) 446 if existingApp.Type != "git-app" {
447 binaryDest := fmt.Sprintf("/usr/local/bin/%s", opts.Name) 447 // Regenerate systemd unit
448 serviceContent, err := templates.SystemdService(map[string]string{ 448 fmt.Println("-> Updating systemd service...")
449 "Name": opts.Name, 449 workDir := fmt.Sprintf("/var/lib/%s", opts.Name)
450 "User": opts.Name, 450 binaryDest := fmt.Sprintf("/usr/local/bin/%s", opts.Name)
451 "WorkDir": workDir, 451 serviceContent, err := templates.SystemdService(map[string]string{
452 "BinaryPath": binaryDest, 452 "Name": opts.Name,
453 "Port": strconv.Itoa(existingApp.Port), 453 "User": opts.Name,
454 "EnvFile": envFilePath, 454 "WorkDir": workDir,
455 "Args": opts.Args, 455 "BinaryPath": binaryDest,
456 "Memory": opts.Memory, 456 "Port": strconv.Itoa(existingApp.Port),
457 "CPU": opts.CPU, 457 "EnvFile": envFilePath,
458 }) 458 "Args": opts.Args,
459 if err != nil { 459 "Memory": opts.Memory,
460 return fmt.Errorf("error generating systemd unit: %w", err) 460 "CPU": opts.CPU,
461 } 461 })
462 if err != nil {
463 return fmt.Errorf("error generating systemd unit: %w", err)
464 }
462 465
463 servicePath := fmt.Sprintf("/etc/systemd/system/%s.service", opts.Name) 466 servicePath := fmt.Sprintf("/etc/systemd/system/%s.service", opts.Name)
464 if err := client.WriteSudoFile(servicePath, serviceContent); err != nil { 467 if err := client.WriteSudoFile(servicePath, serviceContent); err != nil {
465 return fmt.Errorf("error creating systemd unit: %w", err) 468 return fmt.Errorf("error creating systemd unit: %w", err)
466 } 469 }
467 470
468 fmt.Println("-> Reloading systemd...") 471 fmt.Println("-> Reloading systemd...")
469 if _, err := client.RunSudo("systemctl daemon-reload"); err != nil { 472 if _, err := client.RunSudo("systemctl daemon-reload"); err != nil {
470 return fmt.Errorf("error reloading systemd: %w", err) 473 return fmt.Errorf("error reloading systemd: %w", err)
474 }
471 } 475 }
472 476
473 fmt.Println("-> Restarting service...") 477 fmt.Println("-> Restarting service...")