diff options
| author | bndw <ben@bdw.to> | 2026-01-24 16:55:52 -0800 |
|---|---|---|
| committer | bndw <ben@bdw.to> | 2026-01-24 16:55:52 -0800 |
| commit | 8a3cff0dd7eb88cadb73a6df4e14f85450d63317 (patch) | |
| tree | 461e3b7af3a71f92c8a916f2e4578a63e2d92f13 /cmd/ship/host/set_domain.go | |
| parent | 9c222e3fe49c6786c1719b6100564d413d7f8db6 (diff) | |
Add auto-generated subdomain feature
When a base domain is configured on a host (e.g., apps.example.com),
deployments automatically get a subdomain ({name}.apps.example.com).
Custom --domain can still be provided to route both domains.
- Add BaseDomain field to Host state
- Add --base-domain flag to host init
- Add 'ship host set-domain' command to update base domain
- Update deploy flow to auto-generate subdomains
- Fix error display (errors were being silently swallowed)
- Remove placeholder email from Caddyfile template
Diffstat (limited to 'cmd/ship/host/set_domain.go')
| -rw-r--r-- | cmd/ship/host/set_domain.go | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/cmd/ship/host/set_domain.go b/cmd/ship/host/set_domain.go new file mode 100644 index 0000000..fed3b31 --- /dev/null +++ b/cmd/ship/host/set_domain.go | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | package host | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "fmt" | ||
| 5 | |||
| 6 | "github.com/bdw/ship/internal/state" | ||
| 7 | "github.com/spf13/cobra" | ||
| 8 | ) | ||
| 9 | |||
| 10 | var setDomainCmd = &cobra.Command{ | ||
| 11 | Use: "set-domain [domain]", | ||
| 12 | Short: "Set base domain for auto-generated subdomains", | ||
| 13 | Long: `Set the base domain used to auto-generate subdomains for deployments. | ||
| 14 | |||
| 15 | When a base domain is configured (e.g., apps.example.com), every deployment | ||
| 16 | will automatically get a subdomain ({name}.apps.example.com). | ||
| 17 | |||
| 18 | Examples: | ||
| 19 | ship host set-domain apps.example.com # Set base domain | ||
| 20 | ship host set-domain --clear # Remove base domain`, | ||
| 21 | RunE: runSetDomain, | ||
| 22 | } | ||
| 23 | |||
| 24 | func init() { | ||
| 25 | setDomainCmd.Flags().Bool("clear", false, "Clear the base domain") | ||
| 26 | } | ||
| 27 | |||
| 28 | func runSetDomain(cmd *cobra.Command, args []string) error { | ||
| 29 | st, err := state.Load() | ||
| 30 | if err != nil { | ||
| 31 | return fmt.Errorf("error loading state: %w", err) | ||
| 32 | } | ||
| 33 | |||
| 34 | host, _ := cmd.Flags().GetString("host") | ||
| 35 | if host == "" { | ||
| 36 | host = st.GetDefaultHost() | ||
| 37 | } | ||
| 38 | |||
| 39 | if host == "" { | ||
| 40 | return fmt.Errorf("--host is required") | ||
| 41 | } | ||
| 42 | |||
| 43 | clear, _ := cmd.Flags().GetBool("clear") | ||
| 44 | |||
| 45 | if !clear && len(args) == 0 { | ||
| 46 | // Show current base domain | ||
| 47 | hostState := st.GetHost(host) | ||
| 48 | if hostState.BaseDomain == "" { | ||
| 49 | fmt.Printf("No base domain configured for %s\n", host) | ||
| 50 | } else { | ||
| 51 | fmt.Printf("Base domain for %s: %s\n", host, hostState.BaseDomain) | ||
| 52 | } | ||
| 53 | return nil | ||
| 54 | } | ||
| 55 | |||
| 56 | hostState := st.GetHost(host) | ||
| 57 | |||
| 58 | if clear { | ||
| 59 | hostState.BaseDomain = "" | ||
| 60 | if err := st.Save(); err != nil { | ||
| 61 | return fmt.Errorf("error saving state: %w", err) | ||
| 62 | } | ||
| 63 | fmt.Printf("Cleared base domain for %s\n", host) | ||
| 64 | return nil | ||
| 65 | } | ||
| 66 | |||
| 67 | hostState.BaseDomain = args[0] | ||
| 68 | if err := st.Save(); err != nil { | ||
| 69 | return fmt.Errorf("error saving state: %w", err) | ||
| 70 | } | ||
| 71 | |||
| 72 | fmt.Printf("Set base domain for %s: %s\n", host, args[0]) | ||
| 73 | fmt.Println("\nNew deployments will automatically use subdomains like:") | ||
| 74 | fmt.Printf(" myapp.%s\n", args[0]) | ||
| 75 | return nil | ||
| 76 | } | ||
