v2.31.0-dev21 b59533b

config.go RawHistoryFolder

1package cli
2
3import (
4	"context"
5	"fmt"
6	"io"
7	"sort"
8
9	"github.com/bnema/gordon/internal/adapters/in/cli/remote"
10	"github.com/bnema/gordon/internal/adapters/in/cli/ui/components"
11	"github.com/spf13/cobra"
12)
13
14func newConfigCmd() *cobra.Command {
15	cmd := &cobra.Command{
16		Use:   "config",
17		Short: "Inspect Gordon configuration",
18	}
19
20	cmd.AddCommand(newConfigShowCmd())
21
22	return cmd
23}
24
25func newConfigShowCmd() *cobra.Command {
26	var jsonOut bool
27
28	cmd := &cobra.Command{
29		Use:   "show",
30		Short: "Show server configuration",
31		Long: `Display the full Gordon server configuration including server settings,
32auto-route, network isolation, routes, and external routes.
33
34Examples:
35  gordon config show
36  gordon config show --json
37  gordon config show --remote https://gordon.mydomain.com --token $TOKEN`,
38		RunE: func(cmd *cobra.Command, _ []string) error {
39			ctx := cmd.Context()
40			handle, err := resolveControlPlane(configPath)
41			if err != nil {
42				return err
43			}
44			defer handle.close()
45			return runConfigShow(ctx, handle.plane, cmd.OutOrStdout(), jsonOut)
46		},
47	}
48
49	cmd.Flags().BoolVar(&jsonOut, "json", false, "Output as JSON")
50
51	return cmd
52}
53
54func runConfigShow(ctx context.Context, cp ControlPlane, out io.Writer, jsonOut bool) error {
55	config, err := cp.GetConfig(ctx)
56	if err != nil {
57		return fmt.Errorf("failed to get config: %w", err)
58	}
59
60	if config == nil {
61		return fmt.Errorf("no config available")
62	}
63
64	if jsonOut {
65		return writeJSON(out, config)
66	}
67
68	return renderConfigTable(out, config)
69}
70
71func renderConfigTable(out io.Writer, config *remote.Config) error {
72	if err := renderConfigSummary(out, config); err != nil {
73		return err
74	}
75	if err := renderConfigRoutes(out, config); err != nil {
76		return err
77	}
78	return renderConfigExternalRoutes(out, config)
79}
80
81func renderConfigSummary(out io.Writer, config *remote.Config) error {
82	if err := cliWriteLine(out, cliRenderTitle("Gordon Configuration")); err != nil {
83		return err
84	}
85	if err := cliWriteLine(out, ""); err != nil {
86		return err
87	}
88	if err := cliWriteLine(out, cliRenderMeta("Server Port:", fmt.Sprintf("%d", config.Server.Port))); err != nil {
89		return err
90	}
91	if err := cliWriteLine(out, cliRenderMeta("Registry Port:", fmt.Sprintf("%d", config.Server.RegistryPort))); err != nil {
92		return err
93	}
94	if err := cliWriteLine(out, cliRenderMeta("Registry Domain:", config.Server.RegistryDomain)); err != nil {
95		return err
96	}
97	if config.Server.DataDir != "" {
98		if err := cliWriteLine(out, cliRenderMeta("Data Directory:", config.Server.DataDir)); err != nil {
99			return err
100		}
101	}
102	if err := cliWriteLine(out, cliRenderMeta("Auto-Route:", fmt.Sprintf("%v", config.AutoRoute.Enabled))); err != nil {
103		return err
104	}
105	if err := cliWriteLine(out, cliRenderMeta("Network Isolation:", fmt.Sprintf("%v", config.NetworkIsolation.Enabled))); err != nil {
106		return err
107	}
108	if config.NetworkIsolation.Prefix != "" {
109		if err := cliWriteLine(out, cliRenderMeta("Network Prefix:", config.NetworkIsolation.Prefix)); err != nil {
110			return err
111		}
112	}
113	return nil
114}
115
116func renderConfigRoutes(out io.Writer, config *remote.Config) error {
117	if err := cliWriteLine(out, ""); err != nil {
118		return err
119	}
120	if len(config.Routes) == 0 {
121		if err := cliWriteLine(out, cliRenderMuted("No routes configured")); err != nil {
122			return err
123		}
124	} else {
125		if err := cliWriteLine(out, cliRenderTitle("Routes")); err != nil {
126			return err
127		}
128		rows := make([][]string, 0, len(config.Routes))
129		for _, route := range config.Routes {
130			rows = append(rows, []string{route.Domain, route.Image})
131		}
132		table := components.NewTable(
133			components.WithColumns([]components.TableColumn{
134				{Title: "Domain", Width: 30},
135				{Title: "Image", Width: 45},
136			}),
137			components.WithRows(rows),
138		)
139		if err := cliWriteLine(out, table.View()); err != nil {
140			return err
141		}
142	}
143	return nil
144}
145
146func renderConfigExternalRoutes(out io.Writer, config *remote.Config) error {
147	if err := cliWriteLine(out, ""); err != nil {
148		return err
149	}
150	if len(config.ExternalRoutes) == 0 {
151		if err := cliWriteLine(out, cliRenderTitle("External Routes")); err != nil {
152			return err
153		}
154		return cliWriteLine(out, cliRenderMuted("No external routes configured"))
155	}
156
157	if err := cliWriteLine(out, cliRenderTitle("External Routes")); err != nil {
158		return err
159	}
160	routes := append([]remote.ExternalRoute(nil), config.ExternalRoutes...)
161	sort.Slice(routes, func(i, j int) bool { return routes[i].Domain < routes[j].Domain })
162
163	rows := make([][]string, 0, len(routes))
164	for _, route := range routes {
165		target := route.Target
166		if target == "" {
167			target = "[redacted]"
168		}
169		rows = append(rows, []string{route.Domain, target})
170	}
171	table := components.NewTable(
172		components.WithColumns([]components.TableColumn{
173			{Title: "Domain", Width: 30},
174			{Title: "Target", Width: 45},
175		}),
176		components.WithRows(rows),
177	)
178	return cliWriteLine(out, table.View())
179}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close