detached b84b07f

fix(preview): docs corrections, test error handling, and config warning

- Replace invalid Go duration "7d" with "168h" in docs/config/preview.md
- Fix pr-* naming examples: stripped prefix means pr-42 → 42--app.example.com
- Add language specifier to fenced code block in docs/deployment/gitlab-ci.md
- Check errors from svc.List in integration tests (was silently discarding)
- Log warning when preview TTL parsing fails in config/service.go
commit
b84b07f20aeba1bc20ae406f128f7bb57192f969
author
brice · · 2026-03-19 05:27 UTC
parent
e2d78b5
signature
unsigned
4 files · +17 -11
M docs/config/preview.md +7 -7
@@ -33,7 +33,7 @@ The `ttl` field accepts Go duration strings:
3333 |-------|---------|
3434 | `"24h"` | 24 hours |
3535 | `"48h"` | 48 hours (default) |
36-| `"7d"` | 7 days |
36+| `"168h"` | 7 days |
3737 | `"0"` | Never expire (manual deletion only) |
3838
3939 ### `tag_patterns` Matching
@@ -59,7 +59,7 @@ For example, with `separator = "--"` and base route `app.example.com`:
5959 | Image Tag | Preview Domain |
6060 |-----------|----------------|
6161 | `preview-my-feature` | `my-feature--app.example.com` |
62-| `pr-42` | `pr-42--app.example.com` |
62+| `pr-42` | `42--app.example.com` |
6363 | `preview-fix-login` | `fix-login--app.example.com` |
6464
6565 The tag prefix matched by `tag_patterns` is stripped to keep domains short. Slashes in tags are replaced with hyphens.
@@ -138,7 +138,7 @@ jobs:
138138 issue_number: context.issue.number,
139139 owner: context.repo.owner,
140140 repo: context.repo.repo,
141- body: `Preview deployed: https://pr-${{ github.event.pull_request.number }}--app.example.com`
141+ body: `Preview deployed: https://${{ github.event.pull_request.number }}--app.example.com`
142142 })
143143 ```
144144
@@ -166,9 +166,9 @@ jobs:
166166 steps:
167167 - name: Delete preview environment
168168 env:
169- TAG: pr-${{ github.event.pull_request.number }}
169+ PR_NUMBER: ${{ github.event.pull_request.number }}
170170 run: |
171- gordon --server ${{ vars.GORDON_SERVER }} preview delete ${TAG}--app.example.com
171+ gordon --server ${{ vars.GORDON_SERVER }} preview delete ${PR_NUMBER}--app.example.com
172172 ```
173173
174174 ## Lifecycle
@@ -227,8 +227,8 @@ preserve = false
227227 ```
228228
229229 With this config:
230-- Pushing `myapp:pr-99` creates `pr-99--app.example.com` with cloned volumes
231-- Pushing `myapi:preview-auth-refactor` creates `preview-auth-refactor--api.example.com`
230+- Pushing `myapp:pr-99` creates `99--app.example.com` with cloned volumes
231+- Pushing `myapi:preview-auth-refactor` creates `auth-refactor--api.example.com`
232232 - Both previews expire after 48 hours and volumes are removed on teardown
233233
234234 ## Related
@@ -33,7 +33,7 @@ The `ttl` field accepts Go duration strings:
33 |-------|---------|33 |-------|---------|
34 | `"24h"` | 24 hours |34 | `"24h"` | 24 hours |
35 | `"48h"` | 48 hours (default) |35 | `"48h"` | 48 hours (default) |
36-| `"7d"` | 7 days |36+| `"168h"` | 7 days |
37 | `"0"` | Never expire (manual deletion only) |37 | `"0"` | Never expire (manual deletion only) |
38 38
39 ### `tag_patterns` Matching39 ### `tag_patterns` Matching
@@ -59,7 +59,7 @@ For example, with `separator = "--"` and base route `app.example.com`:
59 | Image Tag | Preview Domain |59 | Image Tag | Preview Domain |
60 |-----------|----------------|60 |-----------|----------------|
61 | `preview-my-feature` | `my-feature--app.example.com` |61 | `preview-my-feature` | `my-feature--app.example.com` |
62-| `pr-42` | `pr-42--app.example.com` |62+| `pr-42` | `42--app.example.com` |
63 | `preview-fix-login` | `fix-login--app.example.com` |63 | `preview-fix-login` | `fix-login--app.example.com` |
64 64
65 The tag prefix matched by `tag_patterns` is stripped to keep domains short. Slashes in tags are replaced with hyphens.65 The tag prefix matched by `tag_patterns` is stripped to keep domains short. Slashes in tags are replaced with hyphens.
@@ -138,7 +138,7 @@ jobs:
138 issue_number: context.issue.number,138 issue_number: context.issue.number,
139 owner: context.repo.owner,139 owner: context.repo.owner,
140 repo: context.repo.repo,140 repo: context.repo.repo,
141- body: `Preview deployed: https://pr-${{ github.event.pull_request.number }}--app.example.com`141+ body: `Preview deployed: https://${{ github.event.pull_request.number }}--app.example.com`
142 })142 })
143 ```143 ```
144 144
@@ -166,9 +166,9 @@ jobs:
166 steps:166 steps:
167 - name: Delete preview environment167 - name: Delete preview environment
168 env:168 env:
169- TAG: pr-${{ github.event.pull_request.number }}169+ PR_NUMBER: ${{ github.event.pull_request.number }}
170 run: |170 run: |
171- gordon --server ${{ vars.GORDON_SERVER }} preview delete ${TAG}--app.example.com171+ gordon --server ${{ vars.GORDON_SERVER }} preview delete ${PR_NUMBER}--app.example.com
172 ```172 ```
173 173
174 ## Lifecycle174 ## Lifecycle
@@ -227,8 +227,8 @@ preserve = false
227 ```227 ```
228 228
229 With this config:229 With this config:
230-- Pushing `myapp:pr-99` creates `pr-99--app.example.com` with cloned volumes230+- Pushing `myapp:pr-99` creates `99--app.example.com` with cloned volumes
231-- Pushing `myapi:preview-auth-refactor` creates `preview-auth-refactor--api.example.com`231+- Pushing `myapi:preview-auth-refactor` creates `auth-refactor--api.example.com`
232 - Both previews expire after 48 hours and volumes are removed on teardown232 - Both previews expire after 48 hours and volumes are removed on teardown
233 233
234 ## Related234 ## Related
M docs/deployment/gitlab-ci.md +1 -1
@@ -181,7 +181,7 @@ Gordon automatically detects the version tag from GitLab CI environment variable
181181
182182 ### Authentication Failed
183183
184-```
184+```text
185185 Error: failed to verify token
186186 ```
187187
@@ -181,7 +181,7 @@ Gordon automatically detects the version tag from GitLab CI environment variable
181 181
182 ### Authentication Failed182 ### Authentication Failed
183 183
184-```184+```text
185 Error: failed to verify token185 Error: failed to verify token
186 ```186 ```
187 187
M internal/usecase/auto/preview/integration_test.go +4 -2
@@ -50,7 +50,8 @@ func TestPreviewLifecycle_Integration(t *testing.T) {
5050 err = svc.Delete(ctx, "test-feat")
5151 require.NoError(t, err)
5252
53- all, _ = svc.List(ctx)
53+ all, err = svc.List(ctx)
54+ require.NoError(t, err)
5455 assert.Empty(t, all)
5556 }
5657
@@ -83,6 +84,7 @@ func TestPreviewLifecycle_CleanupExpired(t *testing.T) {
8384 assert.Equal(t, "short-lived", expired[0].Name)
8485
8586 // Should be gone
86- all, _ := svc.List(ctx)
87+ all, err := svc.List(ctx)
88+ require.NoError(t, err)
8789 assert.Empty(t, all)
8890 }
@@ -50,7 +50,8 @@ func TestPreviewLifecycle_Integration(t *testing.T) {
50 err = svc.Delete(ctx, "test-feat")50 err = svc.Delete(ctx, "test-feat")
51 require.NoError(t, err)51 require.NoError(t, err)
52 52
53- all, _ = svc.List(ctx)53+ all, err = svc.List(ctx)
54+ require.NoError(t, err)
54 assert.Empty(t, all)55 assert.Empty(t, all)
55 }56 }
56 57
@@ -83,6 +84,7 @@ func TestPreviewLifecycle_CleanupExpired(t *testing.T) {
83 assert.Equal(t, "short-lived", expired[0].Name)84 assert.Equal(t, "short-lived", expired[0].Name)
84 85
85 // Should be gone86 // Should be gone
86- all, _ := svc.List(ctx)87+ all, err := svc.List(ctx)
88+ require.NoError(t, err)
87 assert.Empty(t, all)89 assert.Empty(t, all)
88 }90 }
M internal/usecase/config/service.go +5 -1
@@ -139,7 +139,11 @@ func (s *Service) loadConfigValues() Config {
139139
140140 // Preview config
141141 previewTTLStr := s.viper.GetString("auto.preview.ttl")
142- previewTTL, _ := time.ParseDuration(previewTTLStr)
142+ previewTTL, err := time.ParseDuration(previewTTLStr)
143+ if err != nil && previewTTLStr != "" {
144+ log := zerowrap.FromCtx(context.Background())
145+ log.Warn().Err(err).Str("ttl", previewTTLStr).Msg("invalid preview TTL format, using default 48h (use Go duration strings, e.g. \"168h\" for 7 days)")
146+ }
143147 if previewTTL == 0 {
144148 previewTTL = 48 * time.Hour
145149 }
@@ -139,7 +139,11 @@ func (s *Service) loadConfigValues() Config {
139 139
140 // Preview config140 // Preview config
141 previewTTLStr := s.viper.GetString("auto.preview.ttl")141 previewTTLStr := s.viper.GetString("auto.preview.ttl")
142- previewTTL, _ := time.ParseDuration(previewTTLStr)142+ previewTTL, err := time.ParseDuration(previewTTLStr)
143+ if err != nil && previewTTLStr != "" {
144+ log := zerowrap.FromCtx(context.Background())
145+ log.Warn().Err(err).Str("ttl", previewTTLStr).Msg("invalid preview TTL format, using default 48h (use Go duration strings, e.g. \"168h\" for 7 days)")
146+ }
143 if previewTTL == 0 {147 if previewTTL == 0 {
144 previewTTL = 48 * time.Hour148 previewTTL = 48 * time.Hour
145 }149 }

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