v2.31.0-dev16 8d0a092

orphans.go RawHistoryFolder

1package preview
2
3import (
4	"path/filepath"
5	"strings"
6	"time"
7
8	"github.com/bnema/gordon/internal/domain"
9)
10
11const orphanGracePeriod = 5 * time.Minute
12
13// IsOrphanPreview returns true if the container looks like a preview (by image
14// tag pattern and domain separator) but is not in the tracked preview list.
15// Containers younger than 5 minutes are skipped to avoid racing with
16// CreatePreview.
17func IsOrphanPreview(c *domain.Container, tracked []domain.PreviewRoute, tagPatterns []string, separator string) bool {
18	imgLabel := c.Labels[domain.LabelImage]
19	domLabel := c.Labels[domain.LabelDomain]
20	if imgLabel == "" || domLabel == "" {
21		return false
22	}
23
24	// Grace period: skip very recent containers.
25	if !c.Created.IsZero() && time.Since(c.Created) < orphanGracePeriod {
26		return false
27	}
28
29	// Condition 1: image tag matches a preview pattern.
30	tag := tagFromImage(imgLabel)
31	if !matchesAnyPattern(tag, tagPatterns) {
32		return false
33	}
34
35	// Condition 2: domain contains the separator.
36	if !strings.Contains(domLabel, separator) {
37		return false
38	}
39
40	// Not an orphan if tracked.
41	for _, p := range tracked {
42		if p.Domain == domLabel {
43			return false
44		}
45	}
46	return true
47}
48
49// IsExpiredOrphan returns true if the container has exceeded the TTL based on
50// its creation time.
51func IsExpiredOrphan(c *domain.Container, ttl time.Duration) bool {
52	if c.Created.IsZero() {
53		return false // unknown creation time — don't delete, play it safe
54	}
55	return time.Since(c.Created) > ttl
56}
57
58// tagFromImage extracts the tag portion from an image reference.
59// "myapp:preview-feat" -> "preview-feat"
60// "registry.example.com/myapp:preview-feat" -> "preview-feat"
61// "myapp" -> "" (no tag)
62func tagFromImage(image string) string {
63	if idx := strings.Index(image, "@"); idx != -1 {
64		return ""
65	}
66	if idx := strings.LastIndex(image, ":"); idx != -1 {
67		return image[idx+1:]
68	}
69	return ""
70}
71
72// matchesAnyPattern checks if the tag matches any of the glob patterns.
73func matchesAnyPattern(tag string, patterns []string) bool {
74	for _, p := range patterns {
75		if matched, _ := filepath.Match(p, tag); matched {
76			return true
77		}
78	}
79	return false
80}

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