detached d6ce1c7

feat: add gordon routes show command

commit
d6ce1c7e35dcfadea7ec51176b83c8be60dbc06a
author
brice · · 2026-03-14 03:21 UTC
parent
b7cdfee
signature
unsigned
2 files · +140 -0
M docs/cli/routes.md +56 -0
@@ -12,6 +12,7 @@ Use `--remote` and `--token` to override. See [CLI Overview](./index.md).
1212 | Subcommand | Description |
1313 |------------|-------------|
1414 | `list` | List all routes |
15+| `show` | Show details for a single route |
1516 | `add` | Create or update a route |
1617 | `remove` | Remove a route |
1718 | `deploy` | Deploy a specific route |
@@ -116,6 +117,61 @@ gordon routes add myapp.example.com myapp:latest --remote https://gordon.mydomai
116117
117118 ---
118119
120+## gordon routes show
121+
122+Show detailed information about a single route.
123+
124+```bash
125+gordon routes show <domain>
126+gordon routes show myapp.example.com
127+gordon routes show myapp.example.com --json
128+```
129+
130+### Arguments
131+
132+| Argument | Description |
133+|----------|-------------|
134+| `<domain>` | The domain name of the route to inspect |
135+
136+### Options
137+
138+| Option | Description |
139+|--------|-------------|
140+| `--json` | Output route details as JSON |
141+| `--remote` | Remote Gordon URL |
142+| `--token` | Authentication token for remote |
143+
144+### Description
145+
146+Displays the configured image for the route plus any available container and HTTP health information.
147+In local-only mode, health data may be unavailable.
148+
149+### Examples
150+
151+```bash
152+# Local
153+gordon routes show myapp.example.com
154+
155+# JSON
156+gordon routes show myapp.example.com --json
157+
158+# Remote (override)
159+gordon routes show myapp.example.com --remote https://gordon.mydomain.com --token $TOKEN
160+```
161+
162+### JSON Output
163+
164+```json
165+{
166+ "domain": "myapp.example.com",
167+ "image": "myapp:latest",
168+ "container_status": "running",
169+ "http_status": 200
170+}
171+```
172+
173+---
174+
119175 ## gordon routes remove
120176
121177 Remove a route.
@@ -12,6 +12,7 @@ Use `--remote` and `--token` to override. See [CLI Overview](./index.md).
12 | Subcommand | Description |12 | Subcommand | Description |
13 |------------|-------------|13 |------------|-------------|
14 | `list` | List all routes |14 | `list` | List all routes |
15+| `show` | Show details for a single route |
15 | `add` | Create or update a route |16 | `add` | Create or update a route |
16 | `remove` | Remove a route |17 | `remove` | Remove a route |
17 | `deploy` | Deploy a specific route |18 | `deploy` | Deploy a specific route |
@@ -116,6 +117,61 @@ gordon routes add myapp.example.com myapp:latest --remote https://gordon.mydomai
116 117
117 ---118 ---
118 119
120+## gordon routes show
121+
122+Show detailed information about a single route.
123+
124+```bash
125+gordon routes show <domain>
126+gordon routes show myapp.example.com
127+gordon routes show myapp.example.com --json
128+```
129+
130+### Arguments
131+
132+| Argument | Description |
133+|----------|-------------|
134+| `<domain>` | The domain name of the route to inspect |
135+
136+### Options
137+
138+| Option | Description |
139+|--------|-------------|
140+| `--json` | Output route details as JSON |
141+| `--remote` | Remote Gordon URL |
142+| `--token` | Authentication token for remote |
143+
144+### Description
145+
146+Displays the configured image for the route plus any available container and HTTP health information.
147+In local-only mode, health data may be unavailable.
148+
149+### Examples
150+
151+```bash
152+# Local
153+gordon routes show myapp.example.com
154+
155+# JSON
156+gordon routes show myapp.example.com --json
157+
158+# Remote (override)
159+gordon routes show myapp.example.com --remote https://gordon.mydomain.com --token $TOKEN
160+```
161+
162+### JSON Output
163+
164+```json
165+{
166+ "domain": "myapp.example.com",
167+ "image": "myapp:latest",
168+ "container_status": "running",
169+ "http_status": 200
170+}
171+```
172+
173+---
174+
119 ## gordon routes remove175 ## gordon routes remove
120 176
121 Remove a route.177 Remove a route.
M internal/adapters/in/cli/routes.go +84 -0
@@ -83,6 +83,7 @@ the local Gordon configuration.`,
8383 }
8484
8585 cmd.AddCommand(newRoutesListCmd())
86+ cmd.AddCommand(newRoutesShowCmd())
8687 cmd.AddCommand(newRoutesAddCmd())
8788 cmd.AddCommand(newRoutesRemoveCmd())
8889
@@ -133,6 +134,89 @@ func newRoutesListCmd() *cobra.Command {
133134 return cmd
134135 }
135136
137+func newRoutesShowCmd() *cobra.Command {
138+ var jsonOut bool
139+
140+ cmd := &cobra.Command{
141+ Use: "show <domain>",
142+ Short: "Show details for a single route",
143+ Long: `Display detailed information about a specific route including its image,
144+container status, and health.
145+
146+Examples:
147+ gordon routes show app.mydomain.com
148+ gordon routes show app.mydomain.com --json
149+ gordon routes show app.mydomain.com --remote https://gordon.mydomain.com`,
150+ Args: cobra.ExactArgs(1),
151+ RunE: func(cmd *cobra.Command, args []string) error {
152+ ctx := context.Background()
153+ handle, err := resolveControlPlane(configPath)
154+ if err != nil {
155+ return err
156+ }
157+ defer handle.close()
158+ return runRoutesShow(ctx, handle.plane, cmd.OutOrStdout(), args[0], jsonOut)
159+ },
160+ }
161+
162+ cmd.Flags().BoolVar(&jsonOut, "json", false, "Output as JSON")
163+
164+ return cmd
165+}
166+
167+func runRoutesShow(ctx context.Context, cp ControlPlane, out io.Writer, routeDomain string, jsonOut bool) error {
168+ route, err := cp.GetRoute(ctx, routeDomain)
169+ if err != nil {
170+ return fmt.Errorf("route not found: %w", err)
171+ }
172+
173+ health, _ := cp.GetHealth(ctx)
174+ var routeHealth *remote.RouteHealth
175+ if health != nil {
176+ routeHealth = health[routeDomain]
177+ }
178+
179+ containerStatus := "unknown"
180+ httpStatus := 0
181+ if routeHealth != nil {
182+ containerStatus = routeHealth.ContainerStatus
183+ httpStatus = routeHealth.HTTPStatus
184+ }
185+
186+ if jsonOut {
187+ payload := map[string]any{
188+ "domain": route.Domain,
189+ "image": route.Image,
190+ "container_status": containerStatus,
191+ "http_status": httpStatus,
192+ }
193+ return writeJSON(out, payload)
194+ }
195+
196+ if err := cliWriteLine(out, cliRenderTitle("Route: "+route.Domain)); err != nil {
197+ return err
198+ }
199+ if err := cliWriteLine(out, ""); err != nil {
200+ return err
201+ }
202+ if err := cliWriteLine(out, cliRenderMeta("Domain:", route.Domain)); err != nil {
203+ return err
204+ }
205+ if err := cliWriteLine(out, cliRenderMeta("Image:", route.Image)); err != nil {
206+ return err
207+ }
208+ if err := cliWriteLine(out, cliRenderMeta("Container:", containerStatus)); err != nil {
209+ return err
210+ }
211+ if httpStatus > 0 {
212+ if err := cliWriteLine(out, cliRenderMeta("HTTP Status:", fmt.Sprintf("%d", httpStatus))); err != nil {
213+ return err
214+ }
215+ }
216+
217+ return nil
218+}
219+
136220 // runRoutesListRemote lists routes from a remote Gordon instance.
137221 func runRoutesListRemote(ctx context.Context, client *remote.Client, jsonOut bool, out io.Writer) error {
138222 routes, err := client.ListRoutesWithDetails(ctx)
@@ -83,6 +83,7 @@ the local Gordon configuration.`,
83 }83 }
84 84
85 cmd.AddCommand(newRoutesListCmd())85 cmd.AddCommand(newRoutesListCmd())
86+ cmd.AddCommand(newRoutesShowCmd())
86 cmd.AddCommand(newRoutesAddCmd())87 cmd.AddCommand(newRoutesAddCmd())
87 cmd.AddCommand(newRoutesRemoveCmd())88 cmd.AddCommand(newRoutesRemoveCmd())
88 89
@@ -133,6 +134,89 @@ func newRoutesListCmd() *cobra.Command {
133 return cmd134 return cmd
134 }135 }
135 136
137+func newRoutesShowCmd() *cobra.Command {
138+ var jsonOut bool
139+
140+ cmd := &cobra.Command{
141+ Use: "show <domain>",
142+ Short: "Show details for a single route",
143+ Long: `Display detailed information about a specific route including its image,
144+container status, and health.
145+
146+Examples:
147+ gordon routes show app.mydomain.com
148+ gordon routes show app.mydomain.com --json
149+ gordon routes show app.mydomain.com --remote https://gordon.mydomain.com`,
150+ Args: cobra.ExactArgs(1),
151+ RunE: func(cmd *cobra.Command, args []string) error {
152+ ctx := context.Background()
153+ handle, err := resolveControlPlane(configPath)
154+ if err != nil {
155+ return err
156+ }
157+ defer handle.close()
158+ return runRoutesShow(ctx, handle.plane, cmd.OutOrStdout(), args[0], jsonOut)
159+ },
160+ }
161+
162+ cmd.Flags().BoolVar(&jsonOut, "json", false, "Output as JSON")
163+
164+ return cmd
165+}
166+
167+func runRoutesShow(ctx context.Context, cp ControlPlane, out io.Writer, routeDomain string, jsonOut bool) error {
168+ route, err := cp.GetRoute(ctx, routeDomain)
169+ if err != nil {
170+ return fmt.Errorf("route not found: %w", err)
171+ }
172+
173+ health, _ := cp.GetHealth(ctx)
174+ var routeHealth *remote.RouteHealth
175+ if health != nil {
176+ routeHealth = health[routeDomain]
177+ }
178+
179+ containerStatus := "unknown"
180+ httpStatus := 0
181+ if routeHealth != nil {
182+ containerStatus = routeHealth.ContainerStatus
183+ httpStatus = routeHealth.HTTPStatus
184+ }
185+
186+ if jsonOut {
187+ payload := map[string]any{
188+ "domain": route.Domain,
189+ "image": route.Image,
190+ "container_status": containerStatus,
191+ "http_status": httpStatus,
192+ }
193+ return writeJSON(out, payload)
194+ }
195+
196+ if err := cliWriteLine(out, cliRenderTitle("Route: "+route.Domain)); err != nil {
197+ return err
198+ }
199+ if err := cliWriteLine(out, ""); err != nil {
200+ return err
201+ }
202+ if err := cliWriteLine(out, cliRenderMeta("Domain:", route.Domain)); err != nil {
203+ return err
204+ }
205+ if err := cliWriteLine(out, cliRenderMeta("Image:", route.Image)); err != nil {
206+ return err
207+ }
208+ if err := cliWriteLine(out, cliRenderMeta("Container:", containerStatus)); err != nil {
209+ return err
210+ }
211+ if httpStatus > 0 {
212+ if err := cliWriteLine(out, cliRenderMeta("HTTP Status:", fmt.Sprintf("%d", httpStatus))); err != nil {
213+ return err
214+ }
215+ }
216+
217+ return nil
218+}
219+
136 // runRoutesListRemote lists routes from a remote Gordon instance.220 // runRoutesListRemote lists routes from a remote Gordon instance.
137 func runRoutesListRemote(ctx context.Context, client *remote.Client, jsonOut bool, out io.Writer) error {221 func runRoutesListRemote(ctx context.Context, client *remote.Client, jsonOut bool, out io.Writer) error {
138 routes, err := client.ListRoutesWithDetails(ctx)222 routes, err := client.ListRoutesWithDetails(ctx)

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