more knecht
This commit is contained in:
@@ -13,10 +13,14 @@ var listCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List all stacks with status and drift",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
_, client, svcPath, err := setup()
|
||||
cfg, client, svcPath, err := setup()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ignoreSet := make(map[string]bool, len(cfg.Ignore))
|
||||
for _, name := range cfg.Ignore {
|
||||
ignoreSet[name] = true
|
||||
}
|
||||
|
||||
stacks, err := client.ListStacks()
|
||||
if err != nil {
|
||||
@@ -35,7 +39,12 @@ var listCmd = &cobra.Command{
|
||||
fmt.Printf("%-20s %-10s %s\n", "STACK", "STATUS", "DRIFT")
|
||||
fmt.Println(repeat("-", 60))
|
||||
|
||||
remoteNames := make(map[string]bool, len(stacks))
|
||||
for _, s := range stacks {
|
||||
if ignoreSet[s.Name] {
|
||||
continue
|
||||
}
|
||||
remoteNames[s.Name] = true
|
||||
status := statusLabel(s.Status)
|
||||
driftSummary := "no local compose"
|
||||
|
||||
@@ -49,6 +58,14 @@ var listCmd = &cobra.Command{
|
||||
|
||||
fmt.Printf("%-20s %-10s %s\n", s.Name, status, driftSummary)
|
||||
}
|
||||
|
||||
// Local-only stacks
|
||||
for _, l := range locals {
|
||||
if ignoreSet[l.Name] || remoteNames[l.Name] {
|
||||
continue
|
||||
}
|
||||
fmt.Printf("%-20s %-10s %s\n", l.Name, "not deployed", "-")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ var logsCmd = &cobra.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
logsBase := deriveLogsURL(cfg.Portainer.URL)
|
||||
logsBase := deriveLogsURL(cfg.URL)
|
||||
|
||||
if len(args) == 0 {
|
||||
fmt.Printf("Opening %s\n", logsBase)
|
||||
|
||||
@@ -44,7 +44,7 @@ func setup() (*config.Config, *portainer.Client, string, error) {
|
||||
return nil, nil, "", err
|
||||
}
|
||||
|
||||
client, err := portainer.New(cfg.Portainer.URL, cfg.Portainer.Token, cfg.Portainer.Endpoint)
|
||||
client, err := portainer.New(cfg.URL, cfg.Token, cfg.Endpoint)
|
||||
if err != nil {
|
||||
return nil, nil, "", fmt.Errorf("connecting to Portainer: %w", err)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/jensbecker/homelab/knecht/portainer"
|
||||
"github.com/jensbecker/homelab/knecht/stack"
|
||||
"github.com/jensbecker/homelab/knecht/tui"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -37,15 +38,19 @@ var updateCmd = &cobra.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
// Check for missing env keys and prompt for values
|
||||
exampleKeys, err := local.EnvExampleKeys()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
env, err := mergeEnvVars(remote.Env, exampleKeys)
|
||||
|
||||
env, err := mergeEnvVars(name, remote.Env, exampleKeys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if env == nil {
|
||||
fmt.Println("Cancelled.")
|
||||
return nil
|
||||
}
|
||||
|
||||
s, err := client.UpdateStack(remote.ID, compose, env)
|
||||
if err != nil {
|
||||
@@ -56,20 +61,32 @@ var updateCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
// mergeEnvVars takes existing Portainer env vars and prompts for any keys
|
||||
// present in .env.example but missing from Portainer.
|
||||
func mergeEnvVars(existing []portainer.EnvVar, exampleKeys []string) ([]portainer.EnvVar, error) {
|
||||
// mergeEnvVars preserves existing Portainer env vars and prompts via TUI for
|
||||
// any keys present in .env.example but missing from Portainer.
|
||||
// Returns nil if the user cancelled the form.
|
||||
func mergeEnvVars(stackName string, existing []portainer.EnvVar, exampleKeys []string) ([]portainer.EnvVar, error) {
|
||||
envMap := make(map[string]string, len(existing))
|
||||
for _, e := range existing {
|
||||
envMap[e.Name] = e.Value
|
||||
}
|
||||
|
||||
var missing []string
|
||||
for _, key := range exampleKeys {
|
||||
if _, ok := envMap[key]; !ok {
|
||||
fmt.Printf("Missing env var %q — enter value (leave empty to skip): ", key)
|
||||
var val string
|
||||
fmt.Scanln(&val)
|
||||
envMap[key] = val
|
||||
missing = append(missing, key)
|
||||
}
|
||||
}
|
||||
|
||||
if len(missing) > 0 {
|
||||
values, err := tui.PromptMissingEnv(stackName, missing)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if values == nil {
|
||||
return nil, nil // cancelled
|
||||
}
|
||||
for k, v := range values {
|
||||
envMap[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user