detached 351d7d0

fix(images): resolve remaining coderabbit nitpicks

commit
351d7d0b152e62cb53fda40950183b3b46c69e4a
author
brice · · 2026-02-08 07:47 UTC
committer
brice · · 2026-02-08 09:40 UTC
parent
e5e7237
signature
unsigned
4 files · +28 -2
M docs/cli/images.md +2 -0
@@ -37,6 +37,8 @@ Flags:
3737 | `--keep` | `0` | Number of latest tags to keep per repository (`0` disables registry cleanup) |
3838 | `--runtime-only` | `false` | Prune dangling runtime images only; forces registry cleanup off |
3939
40+`--keep` defaults to `0` for ad-hoc CLI safety (registry cleanup off by default), while scheduled pruning uses `images.prune.keep_last` from config (default `3`). Use config for recurring behavior; when a CLI `--keep` value is provided, that request value is used.
41+
4042 Behavior notes:
4143
4244 - `--runtime-only` forces `keep_last = 0`.
@@ -37,6 +37,8 @@ Flags:
37 | `--keep` | `0` | Number of latest tags to keep per repository (`0` disables registry cleanup) |37 | `--keep` | `0` | Number of latest tags to keep per repository (`0` disables registry cleanup) |
38 | `--runtime-only` | `false` | Prune dangling runtime images only; forces registry cleanup off |38 | `--runtime-only` | `false` | Prune dangling runtime images only; forces registry cleanup off |
39 39
40+`--keep` defaults to `0` for ad-hoc CLI safety (registry cleanup off by default), while scheduled pruning uses `images.prune.keep_last` from config (default `3`). Use config for recurring behavior; when a CLI `--keep` value is provided, that request value is used.
41+
40 Behavior notes:42 Behavior notes:
41 43
42 - `--runtime-only` forces `keep_last = 0`.44 - `--runtime-only` forces `keep_last = 0`.
M internal/adapters/out/docker/runtime.go +1 -1
@@ -597,7 +597,7 @@ func (r *Runtime) PruneImages(ctx context.Context, danglingOnly bool) (runtimepk
597597
598598 pruneFilters := filters.NewArgs()
599599 if danglingOnly {
600- pruneFilters.Add("dangling", strconv.FormatBool(true))
600+ pruneFilters.Add("dangling", "true")
601601 }
602602
603603 pruneResult, err := r.client.ImagesPrune(ctx, pruneFilters)
@@ -597,7 +597,7 @@ func (r *Runtime) PruneImages(ctx context.Context, danglingOnly bool) (runtimepk
597 597
598 pruneFilters := filters.NewArgs()598 pruneFilters := filters.NewArgs()
599 if danglingOnly {599 if danglingOnly {
600- pruneFilters.Add("dangling", strconv.FormatBool(true))600+ pruneFilters.Add("dangling", "true")
601 }601 }
602 602
603 pruneResult, err := r.client.ImagesPrune(ctx, pruneFilters)603 pruneResult, err := r.client.ImagesPrune(ctx, pruneFilters)
M internal/usecase/images/service.go +2 -1
@@ -353,7 +353,8 @@ func splitRepoTag(repoTag string) (string, string) {
353353 }
354354
355355 idx := strings.LastIndex(repoTag, ":")
356- if idx <= 0 || idx >= len(repoTag)-1 {
356+ slashIdx := strings.LastIndex(repoTag, "/")
357+ if idx <= slashIdx || idx >= len(repoTag)-1 {
357358 return repoTag, ""
358359 }
359360
@@ -353,7 +353,8 @@ func splitRepoTag(repoTag string) (string, string) {
353 }353 }
354 354
355 idx := strings.LastIndex(repoTag, ":")355 idx := strings.LastIndex(repoTag, ":")
356- if idx <= 0 || idx >= len(repoTag)-1 {356+ slashIdx := strings.LastIndex(repoTag, "/")
357+ if idx <= slashIdx || idx >= len(repoTag)-1 {
357 return repoTag, ""358 return repoTag, ""
358 }359 }
359 360
M internal/usecase/images/service_test.go +23 -0
@@ -614,4 +614,27 @@ func (f *fakeBlobStorage) DeleteBlob(digest string) error {
614614 return nil
615615 }
616616
617+func TestSplitRepoTag(t *testing.T) {
618+ tests := []struct {
619+ name string
620+ input string
621+ wantRepo string
622+ wantTag string
623+ }{
624+ {name: "repository and tag", input: "alpine:latest", wantRepo: "alpine", wantTag: "latest"},
625+ {name: "registry port and tag", input: "localhost:5000/repo:v1", wantRepo: "localhost:5000/repo", wantTag: "v1"},
626+ {name: "registry port without tag", input: "localhost:5000/repo", wantRepo: "localhost:5000/repo", wantTag: ""},
627+ {name: "missing tag", input: "alpine", wantRepo: "alpine", wantTag: ""},
628+ {name: "trailing colon", input: "alpine:", wantRepo: "alpine:", wantTag: ""},
629+ }
630+
631+ for _, tt := range tests {
632+ t.Run(tt.name, func(t *testing.T) {
633+ repo, tag := splitRepoTag(tt.input)
634+ assert.Equal(t, tt.wantRepo, repo)
635+ assert.Equal(t, tt.wantTag, tag)
636+ })
637+ }
638+}
639+
617640 var _ pkgruntime.Runtime = (*fakeRuntime)(nil)
@@ -614,4 +614,27 @@ func (f *fakeBlobStorage) DeleteBlob(digest string) error {
614 return nil614 return nil
615 }615 }
616 616
617+func TestSplitRepoTag(t *testing.T) {
618+ tests := []struct {
619+ name string
620+ input string
621+ wantRepo string
622+ wantTag string
623+ }{
624+ {name: "repository and tag", input: "alpine:latest", wantRepo: "alpine", wantTag: "latest"},
625+ {name: "registry port and tag", input: "localhost:5000/repo:v1", wantRepo: "localhost:5000/repo", wantTag: "v1"},
626+ {name: "registry port without tag", input: "localhost:5000/repo", wantRepo: "localhost:5000/repo", wantTag: ""},
627+ {name: "missing tag", input: "alpine", wantRepo: "alpine", wantTag: ""},
628+ {name: "trailing colon", input: "alpine:", wantRepo: "alpine:", wantTag: ""},
629+ }
630+
631+ for _, tt := range tests {
632+ t.Run(tt.name, func(t *testing.T) {
633+ repo, tag := splitRepoTag(tt.input)
634+ assert.Equal(t, tt.wantRepo, repo)
635+ assert.Equal(t, tt.wantTag, tag)
636+ })
637+ }
638+}
639+
617 var _ pkgruntime.Runtime = (*fakeRuntime)(nil)640 var _ pkgruntime.Runtime = (*fakeRuntime)(nil)

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