summaryrefslogtreecommitdiffstats
path: root/cmd/ship/env
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/ship/env')
-rw-r--r--cmd/ship/env/env.go17
-rw-r--r--cmd/ship/env/list.go72
-rw-r--r--cmd/ship/env/set.go135
-rw-r--r--cmd/ship/env/unset.go95
4 files changed, 0 insertions, 319 deletions
diff --git a/cmd/ship/env/env.go b/cmd/ship/env/env.go
deleted file mode 100644
index 489353a..0000000
--- a/cmd/ship/env/env.go
+++ /dev/null
@@ -1,17 +0,0 @@
1package env
2
3import (
4 "github.com/spf13/cobra"
5)
6
7var Cmd = &cobra.Command{
8 Use: "env",
9 Short: "Manage environment variables",
10 Long: "Manage environment variables for deployed applications",
11}
12
13func init() {
14 Cmd.AddCommand(listCmd)
15 Cmd.AddCommand(setCmd)
16 Cmd.AddCommand(unsetCmd)
17}
diff --git a/cmd/ship/env/list.go b/cmd/ship/env/list.go
deleted file mode 100644
index e94b83a..0000000
--- a/cmd/ship/env/list.go
+++ /dev/null
@@ -1,72 +0,0 @@
1package env
2
3import (
4 "fmt"
5 "strings"
6
7 "github.com/bdw/ship/internal/state"
8 "github.com/spf13/cobra"
9)
10
11var listCmd = &cobra.Command{
12 Use: "list <app>",
13 Short: "List environment variables for an app",
14 Args: cobra.ExactArgs(1),
15 RunE: runList,
16}
17
18func runList(cmd *cobra.Command, args []string) error {
19 name := args[0]
20 if err := state.ValidateName(name); err != nil {
21 return err
22 }
23
24 st, err := state.Load()
25 if err != nil {
26 return fmt.Errorf("error loading state: %w", err)
27 }
28
29 host, _ := cmd.Flags().GetString("host")
30 if host == "" {
31 host = st.GetDefaultHost()
32 }
33
34 if host == "" {
35 return fmt.Errorf("--host is required")
36 }
37
38 app, err := st.GetApp(host, name)
39 if err != nil {
40 return err
41 }
42
43 if app.Type != "app" {
44 return fmt.Errorf("env is only available for apps, not static sites")
45 }
46
47 fmt.Printf("Environment variables for %s:\n\n", name)
48 if len(app.Env) == 0 {
49 fmt.Println(" (none)")
50 } else {
51 for k, v := range app.Env {
52 display := v
53 if isSensitive(k) {
54 display = "***"
55 }
56 fmt.Printf(" %s=%s\n", k, display)
57 }
58 }
59
60 return nil
61}
62
63func isSensitive(key string) bool {
64 key = strings.ToLower(key)
65 sensitiveWords := []string{"key", "secret", "password", "token", "api"}
66 for _, word := range sensitiveWords {
67 if strings.Contains(key, word) {
68 return true
69 }
70 }
71 return false
72}
diff --git a/cmd/ship/env/set.go b/cmd/ship/env/set.go
deleted file mode 100644
index d4292f3..0000000
--- a/cmd/ship/env/set.go
+++ /dev/null
@@ -1,135 +0,0 @@
1package env
2
3import (
4 "bufio"
5 "fmt"
6 "os"
7 "strings"
8
9 "github.com/bdw/ship/internal/ssh"
10 "github.com/bdw/ship/internal/state"
11 "github.com/spf13/cobra"
12)
13
14var setCmd = &cobra.Command{
15 Use: "set <app> KEY=VALUE...",
16 Short: "Set environment variable(s)",
17 Long: "Set one or more environment variables for an app. Variables are specified as KEY=VALUE pairs.",
18 Args: cobra.MinimumNArgs(2),
19 RunE: runSet,
20}
21
22func init() {
23 setCmd.Flags().StringP("file", "f", "", "Load environment from file")
24}
25
26func runSet(cmd *cobra.Command, args []string) error {
27 name := args[0]
28 if err := state.ValidateName(name); err != nil {
29 return err
30 }
31 envVars := args[1:]
32
33 st, err := state.Load()
34 if err != nil {
35 return fmt.Errorf("error loading state: %w", err)
36 }
37
38 host, _ := cmd.Flags().GetString("host")
39 if host == "" {
40 host = st.GetDefaultHost()
41 }
42
43 if host == "" {
44 return fmt.Errorf("--host is required")
45 }
46
47 app, err := st.GetApp(host, name)
48 if err != nil {
49 return err
50 }
51
52 if app.Type != "app" {
53 return fmt.Errorf("env is only available for apps, not static sites")
54 }
55
56 if app.Env == nil {
57 app.Env = make(map[string]string)
58 }
59
60 // Set variables from args
61 for _, e := range envVars {
62 parts := strings.SplitN(e, "=", 2)
63 if len(parts) == 2 {
64 app.Env[parts[0]] = parts[1]
65 fmt.Printf("Set %s\n", parts[0])
66 } else {
67 return fmt.Errorf("invalid format: %s (expected KEY=VALUE)", e)
68 }
69 }
70
71 // Set variables from file if provided
72 envFile, _ := cmd.Flags().GetString("file")
73 if envFile != "" {
74 fileEnv, err := parseEnvFile(envFile)
75 if err != nil {
76 return fmt.Errorf("error reading env file: %w", err)
77 }
78 for k, v := range fileEnv {
79 app.Env[k] = v
80 fmt.Printf("Set %s\n", k)
81 }
82 }
83
84 if err := st.Save(); err != nil {
85 return fmt.Errorf("error saving state: %w", err)
86 }
87
88 client, err := ssh.Connect(host)
89 if err != nil {
90 return fmt.Errorf("error connecting to VPS: %w", err)
91 }
92 defer client.Close()
93
94 fmt.Println("-> Updating environment file on VPS...")
95 envFilePath := fmt.Sprintf("/etc/ship/env/%s.env", name)
96 envContent := ""
97 for k, v := range app.Env {
98 envContent += fmt.Sprintf("%s=%s\n", k, v)
99 }
100 if err := client.WriteSudoFile(envFilePath, envContent); err != nil {
101 return fmt.Errorf("error updating env file: %w", err)
102 }
103
104 fmt.Println("-> Restarting service...")
105 if _, err := client.RunSudo(fmt.Sprintf("systemctl restart %s", name)); err != nil {
106 return fmt.Errorf("error restarting service: %w", err)
107 }
108
109 fmt.Println("Environment variables updated successfully")
110 return nil
111}
112
113func parseEnvFile(path string) (map[string]string, error) {
114 file, err := os.Open(path)
115 if err != nil {
116 return nil, err
117 }
118 defer file.Close()
119
120 env := make(map[string]string)
121 scanner := bufio.NewScanner(file)
122 for scanner.Scan() {
123 line := strings.TrimSpace(scanner.Text())
124 if line == "" || strings.HasPrefix(line, "#") {
125 continue
126 }
127
128 parts := strings.SplitN(line, "=", 2)
129 if len(parts) == 2 {
130 env[parts[0]] = parts[1]
131 }
132 }
133
134 return env, scanner.Err()
135}
diff --git a/cmd/ship/env/unset.go b/cmd/ship/env/unset.go
deleted file mode 100644
index 8292f42..0000000
--- a/cmd/ship/env/unset.go
+++ /dev/null
@@ -1,95 +0,0 @@
1package env
2
3import (
4 "fmt"
5
6 "github.com/bdw/ship/internal/ssh"
7 "github.com/bdw/ship/internal/state"
8 "github.com/spf13/cobra"
9)
10
11var unsetCmd = &cobra.Command{
12 Use: "unset <app> KEY...",
13 Short: "Unset environment variable(s)",
14 Long: "Remove one or more environment variables from an app.",
15 Args: cobra.MinimumNArgs(2),
16 RunE: runUnset,
17}
18
19func runUnset(cmd *cobra.Command, args []string) error {
20 name := args[0]
21 if err := state.ValidateName(name); err != nil {
22 return err
23 }
24 keys := args[1:]
25
26 st, err := state.Load()
27 if err != nil {
28 return fmt.Errorf("error loading state: %w", err)
29 }
30
31 host, _ := cmd.Flags().GetString("host")
32 if host == "" {
33 host = st.GetDefaultHost()
34 }
35
36 if host == "" {
37 return fmt.Errorf("--host is required")
38 }
39
40 app, err := st.GetApp(host, name)
41 if err != nil {
42 return err
43 }
44
45 if app.Type != "app" {
46 return fmt.Errorf("env is only available for apps, not static sites")
47 }
48
49 if app.Env == nil {
50 return fmt.Errorf("no environment variables set")
51 }
52
53 changed := false
54 for _, key := range keys {
55 if _, exists := app.Env[key]; exists {
56 delete(app.Env, key)
57 changed = true
58 fmt.Printf("Unset %s\n", key)
59 } else {
60 fmt.Printf("Warning: %s not found\n", key)
61 }
62 }
63
64 if !changed {
65 return nil
66 }
67
68 if err := st.Save(); err != nil {
69 return fmt.Errorf("error saving state: %w", err)
70 }
71
72 client, err := ssh.Connect(host)
73 if err != nil {
74 return fmt.Errorf("error connecting to VPS: %w", err)
75 }
76 defer client.Close()
77
78 fmt.Println("-> Updating environment file on VPS...")
79 envFilePath := fmt.Sprintf("/etc/ship/env/%s.env", name)
80 envContent := ""
81 for k, v := range app.Env {
82 envContent += fmt.Sprintf("%s=%s\n", k, v)
83 }
84 if err := client.WriteSudoFile(envFilePath, envContent); err != nil {
85 return fmt.Errorf("error updating env file: %w", err)
86 }
87
88 fmt.Println("-> Restarting service...")
89 if _, err := client.RunSudo(fmt.Sprintf("systemctl restart %s", name)); err != nil {
90 return fmt.Errorf("error restarting service: %w", err)
91 }
92
93 fmt.Println("Environment variables updated successfully")
94 return nil
95}