v3.3.1 31f1eec

deploy_error.go RawHistoryFolder

1package cli
2
3import (
4	"errors"
5	"fmt"
6	"regexp"
7	"strings"
8	"unicode"
9
10	"github.com/bnema/gordon/internal/adapters/in/cli/remote"
11	"github.com/bnema/gordon/internal/domain"
12)
13
14var ansiEscapePattern = regexp.MustCompile(`\x1b\[[0-9;?]*[ -/]*[@-~]`)
15
16type renderedDeployFailureError struct {
17	message string
18	err     error
19}
20
21func (e *renderedDeployFailureError) Error() string {
22	return e.message
23}
24
25func (e *renderedDeployFailureError) Unwrap() error {
26	return e.err
27}
28
29func formatDeployFailure(err error) error {
30	if formatted, ok := structuredDeployFailure(err); ok {
31		return formatted
32	}
33
34	return fmt.Errorf("failed to deploy: %w", err)
35}
36
37func structuredDeployFailure(err error) (error, bool) {
38	var deployErr *domain.DeployFailureError
39	if errors.As(err, &deployErr) {
40		return &renderedDeployFailureError{
41			message: renderDeployFailure(deployErr.Summary, deployErr.Cause, deployErr.Hint, deployErr.Logs),
42			err:     deployErr,
43		}, true
44	}
45
46	var httpErr *remote.HTTPError
47	if errors.As(err, &httpErr) && (httpErr.Structured || httpErr.Cause != "" || httpErr.Hint != "" || len(httpErr.Logs) > 0) {
48		return &renderedDeployFailureError{
49			message: renderDeployFailure(httpErr.Body, httpErr.Cause, httpErr.Hint, httpErr.Logs),
50			err:     httpErr,
51		}, true
52	}
53
54	return nil, false
55}
56
57func renderDeployFailure(summary, cause, hint string, logs []string) string {
58	if summary == "" {
59		summary = domain.DefaultDeployFailureSummary
60	}
61
62	var b strings.Builder
63	if summary == domain.DefaultDeployFailureSummary {
64		b.WriteString(summary)
65	} else {
66		b.WriteString(domain.DefaultDeployFailureSummary)
67		b.WriteString(": ")
68		b.WriteString(summary)
69	}
70
71	if cause != "" {
72		b.WriteString("\nCause: ")
73		b.WriteString(cause)
74	}
75	if hint != "" {
76		b.WriteString("\nHint: ")
77		b.WriteString(hint)
78	}
79	cleanedLogs := make([]string, 0, len(logs))
80	for _, line := range logs {
81		if cleanedLine := sanitizeDeployLogLine(line); cleanedLine != "" {
82			cleanedLogs = append(cleanedLogs, cleanedLine)
83		}
84	}
85	if len(cleanedLogs) > 0 {
86		b.WriteString("\n\nRecent container logs:")
87		for _, cleanedLine := range cleanedLogs {
88			b.WriteString("\n  ")
89			b.WriteString(cleanedLine)
90		}
91	}
92
93	return b.String()
94}
95
96func sanitizeDeployLogLine(line string) string {
97	line = ansiEscapePattern.ReplaceAllString(line, "")
98	line = strings.Map(func(r rune) rune {
99		switch {
100		case r == '\t':
101			return r
102		case !unicode.IsPrint(r):
103			return -1
104		default:
105			return r
106		}
107	}, line)
108	return strings.TrimSpace(line)
109}

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