v2.30.1 1983e1b

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 err := cliWriteLine(out, cliRenderMeta("Data Directory:", config.Server.DataDir)); err != nil {
98		return err
99	}
100	if err := cliWriteLine(out, cliRenderMeta("Auto-Route:", fmt.Sprintf("%v", config.AutoRoute.Enabled))); err != nil {
101		return err
102	}
103	if err := cliWriteLine(out, cliRenderMeta("Network Isolation:", fmt.Sprintf("%v", config.NetworkIsolation.Enabled))); err != nil {
104		return err
105	}
106	if config.NetworkIsolation.Prefix != "" {
107		if err := cliWriteLine(out, cliRenderMeta("Network Prefix:", config.NetworkIsolation.Prefix)); err != nil {
108			return err
109		}
110	}
111	return nil
112}
113
114func renderConfigRoutes(out io.Writer, config *remote.Config) error {
115	if err := cliWriteLine(out, ""); err != nil {
116		return err
117	}
118	if len(config.Routes) == 0 {
119		if err := cliWriteLine(out, cliRenderMuted("No routes configured")); err != nil {
120			return err
121		}
122	} else {
123		if err := cliWriteLine(out, cliRenderTitle("Routes")); err != nil {
124			return err
125		}
126		rows := make([][]string, 0, len(config.Routes))
127		for _, route := range config.Routes {
128			rows = append(rows, []string{route.Domain, route.Image})
129		}
130		table := components.NewTable(
131			components.WithColumns([]components.TableColumn{
132				{Title: "Domain", Width: 30},
133				{Title: "Image", Width: 45},
134			}),
135			components.WithRows(rows),
136		)
137		if err := cliWriteLine(out, table.View()); err != nil {
138			return err
139		}
140	}
141	return nil
142}
143
144func renderConfigExternalRoutes(out io.Writer, config *remote.Config) error {
145	if err := cliWriteLine(out, ""); err != nil {
146		return err
147	}
148	if len(config.ExternalRoutes) == 0 {
149		if err := cliWriteLine(out, cliRenderTitle("External Routes")); err != nil {
150			return err
151		}
152		return cliWriteLine(out, cliRenderMuted("No external routes configured"))
153	}
154
155	if err := cliWriteLine(out, cliRenderTitle("External Routes")); err != nil {
156		return err
157	}
158	domains := make([]string, 0, len(config.ExternalRoutes))
159	for d := range config.ExternalRoutes {
160		domains = append(domains, d)
161	}
162	sort.Strings(domains)
163
164	rows := make([][]string, 0, len(domains))
165	for _, d := range domains {
166		rows = append(rows, []string{d, config.ExternalRoutes[d]})
167	}
168	table := components.NewTable(
169		components.WithColumns([]components.TableColumn{
170			{Title: "Domain", Width: 30},
171			{Title: "Target", Width: 45},
172		}),
173		components.WithRows(rows),
174	)
175	return cliWriteLine(out, table.View())
176}

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