detached 28e7d52

fix(cli) reduce fallback and push cyclomatic complexity and fix lint errors

commit
28e7d52a964508a816b4f4bd05ccd2089ff521bb
author
bnema · · 2026-02-06 20:42 UTC
parent
7b5ce70
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +51 -31
M internal/adapters/in/cli/fallback.go +30 -23
@@ -2,35 +2,42 @@ package cli
22
33 import "strings"
44
5-func shouldFallbackToLocal(err error) bool {
6- if err == nil {
7- return false
5+var (
6+ fallbackNetworkErrors = []string{
7+ "connection refused",
8+ "no such host",
9+ "i/o timeout",
10+ "timeout",
811 }
9- msg := strings.ToLower(err.Error())
1012
11- // Retry local signal mode when remote API is unavailable or misrouted.
12- if strings.Contains(msg, "connection refused") ||
13- strings.Contains(msg, "no such host") ||
14- strings.Contains(msg, "i/o timeout") ||
15- strings.Contains(msg, "timeout") {
16- return true
13+ fallbackStatusCodes = []string{
14+ "500", "501", "502", "503", "504", "505",
1715 }
1816
19- if strings.Contains(msg, "500") ||
20- strings.Contains(msg, "501") ||
21- strings.Contains(msg, "502") ||
22- strings.Contains(msg, "503") ||
23- strings.Contains(msg, "504") ||
24- strings.Contains(msg, "505") {
25- return true
17+ fallbackGatewayErrors = []string{
18+ "internal server error",
19+ "service unavailable",
20+ "bad gateway",
21+ "gateway timeout",
2622 }
23+)
2724
28- if strings.Contains(msg, "internal server error") ||
29- strings.Contains(msg, "service unavailable") ||
30- strings.Contains(msg, "bad gateway") ||
31- strings.Contains(msg, "gateway timeout") {
32- return true
25+func containsAny(s string, patterns []string) bool {
26+ for _, p := range patterns {
27+ if strings.Contains(s, p) {
28+ return true
29+ }
3330 }
34-
3531 return false
3632 }
33+
34+func shouldFallbackToLocal(err error) bool {
35+ if err == nil {
36+ return false
37+ }
38+ msg := strings.ToLower(err.Error())
39+
40+ return containsAny(msg, fallbackNetworkErrors) ||
41+ containsAny(msg, fallbackStatusCodes) ||
42+ containsAny(msg, fallbackGatewayErrors)
43+}
@@ -2,35 +2,42 @@ package cli
2 2
3 import "strings"3 import "strings"
4 4
5-func shouldFallbackToLocal(err error) bool {5+var (
6- if err == nil {6+ fallbackNetworkErrors = []string{
7- return false7+ "connection refused",
8+ "no such host",
9+ "i/o timeout",
10+ "timeout",
8 }11 }
9- msg := strings.ToLower(err.Error())
10 12
11- // Retry local signal mode when remote API is unavailable or misrouted.13+ fallbackStatusCodes = []string{
12- if strings.Contains(msg, "connection refused") ||14+ "500", "501", "502", "503", "504", "505",
13- strings.Contains(msg, "no such host") ||
14- strings.Contains(msg, "i/o timeout") ||
15- strings.Contains(msg, "timeout") {
16- return true
17 }15 }
18 16
19- if strings.Contains(msg, "500") ||17+ fallbackGatewayErrors = []string{
20- strings.Contains(msg, "501") ||18+ "internal server error",
21- strings.Contains(msg, "502") ||19+ "service unavailable",
22- strings.Contains(msg, "503") ||20+ "bad gateway",
23- strings.Contains(msg, "504") ||21+ "gateway timeout",
24- strings.Contains(msg, "505") {
25- return true
26 }22 }
23+)
27 24
28- if strings.Contains(msg, "internal server error") ||25+func containsAny(s string, patterns []string) bool {
29- strings.Contains(msg, "service unavailable") ||26+ for _, p := range patterns {
30- strings.Contains(msg, "bad gateway") ||27+ if strings.Contains(s, p) {
31- strings.Contains(msg, "gateway timeout") {28+ return true
32- return true29+ }
33 }30 }
34-
35 return false31 return false
36 }32 }
33+
34+func shouldFallbackToLocal(err error) bool {
35+ if err == nil {
36+ return false
37+ }
38+ msg := strings.ToLower(err.Error())
39+
40+ return containsAny(msg, fallbackNetworkErrors) ||
41+ containsAny(msg, fallbackStatusCodes) ||
42+ containsAny(msg, fallbackGatewayErrors)
43+}
M internal/adapters/in/cli/push.go +21 -8
@@ -57,17 +57,31 @@ Examples:
5757 return cmd
5858 }
5959
60+func resolveDockerfile(dockerfile string, build bool) (string, error) {
61+ if dockerfile != "" && !build {
62+ return "", fmt.Errorf("--file can only be used with --build")
63+ }
64+ if dockerfile == "" {
65+ return "Dockerfile", nil
66+ }
67+ return dockerfile, nil
68+}
69+
70+func resolveImageRefs(registry, imageName, version string) (versionRef, latestRef string) {
71+ versionRef = fmt.Sprintf("%s/%s:%s", registry, imageName, version)
72+ latestRef = fmt.Sprintf("%s/%s:latest", registry, imageName)
73+ return versionRef, latestRef
74+}
75+
6076 func runPush(ctx context.Context, pushDomain, tag string, build bool, platform string, dockerfile string, buildArgs []string, noDeploy bool, noConfirm bool) error {
6177 client, isRemote := GetRemoteClient()
6278 if !isRemote {
6379 return fmt.Errorf("push requires remote mode")
6480 }
6581
66- if dockerfile != "" && !build {
67- return fmt.Errorf("--file can only be used with --build")
68- }
69- if dockerfile == "" {
70- dockerfile = "Dockerfile"
82+ dockerfile, err := resolveDockerfile(dockerfile, build)
83+ if err != nil {
84+ return err
7185 }
7286
7387 route, err := client.GetRoute(ctx, pushDomain)
@@ -93,8 +107,7 @@ func runPush(ctx context.Context, pushDomain, tag string, build bool, platform s
93107 }
94108 }
95109
96- versionRef := fmt.Sprintf("%s/%s:%s", registry, imageName, version)
97- latestRef := fmt.Sprintf("%s/%s:latest", registry, imageName)
110+ versionRef, latestRef := resolveImageRefs(registry, imageName, version)
98111
99112 fmt.Printf("Image: %s\n", styles.Theme.Bold.Render(versionRef))
100113 if version != "latest" {
@@ -133,7 +146,7 @@ func determineVersion(ctx context.Context, tag string) string {
133146
134147 func buildAndPush(ctx context.Context, version, platform, dockerfile string, buildArgs []string, versionRef, latestRef string) error {
135148 if _, err := os.Stat(dockerfile); os.IsNotExist(err) {
136- return fmt.Errorf("Dockerfile not found: %s", dockerfile)
149+ return fmt.Errorf("dockerfile not found: %s", dockerfile)
137150 }
138151
139152 // Build and load into local daemon (NOT --push).
@@ -57,17 +57,31 @@ Examples:
57 return cmd57 return cmd
58 }58 }
59 59
60+func resolveDockerfile(dockerfile string, build bool) (string, error) {
61+ if dockerfile != "" && !build {
62+ return "", fmt.Errorf("--file can only be used with --build")
63+ }
64+ if dockerfile == "" {
65+ return "Dockerfile", nil
66+ }
67+ return dockerfile, nil
68+}
69+
70+func resolveImageRefs(registry, imageName, version string) (versionRef, latestRef string) {
71+ versionRef = fmt.Sprintf("%s/%s:%s", registry, imageName, version)
72+ latestRef = fmt.Sprintf("%s/%s:latest", registry, imageName)
73+ return versionRef, latestRef
74+}
75+
60 func runPush(ctx context.Context, pushDomain, tag string, build bool, platform string, dockerfile string, buildArgs []string, noDeploy bool, noConfirm bool) error {76 func runPush(ctx context.Context, pushDomain, tag string, build bool, platform string, dockerfile string, buildArgs []string, noDeploy bool, noConfirm bool) error {
61 client, isRemote := GetRemoteClient()77 client, isRemote := GetRemoteClient()
62 if !isRemote {78 if !isRemote {
63 return fmt.Errorf("push requires remote mode")79 return fmt.Errorf("push requires remote mode")
64 }80 }
65 81
66- if dockerfile != "" && !build {82+ dockerfile, err := resolveDockerfile(dockerfile, build)
67- return fmt.Errorf("--file can only be used with --build")83+ if err != nil {
68- }84+ return err
69- if dockerfile == "" {
70- dockerfile = "Dockerfile"
71 }85 }
72 86
73 route, err := client.GetRoute(ctx, pushDomain)87 route, err := client.GetRoute(ctx, pushDomain)
@@ -93,8 +107,7 @@ func runPush(ctx context.Context, pushDomain, tag string, build bool, platform s
93 }107 }
94 }108 }
95 109
96- versionRef := fmt.Sprintf("%s/%s:%s", registry, imageName, version)110+ versionRef, latestRef := resolveImageRefs(registry, imageName, version)
97- latestRef := fmt.Sprintf("%s/%s:latest", registry, imageName)
98 111
99 fmt.Printf("Image: %s\n", styles.Theme.Bold.Render(versionRef))112 fmt.Printf("Image: %s\n", styles.Theme.Bold.Render(versionRef))
100 if version != "latest" {113 if version != "latest" {
@@ -133,7 +146,7 @@ func determineVersion(ctx context.Context, tag string) string {
133 146
134 func buildAndPush(ctx context.Context, version, platform, dockerfile string, buildArgs []string, versionRef, latestRef string) error {147 func buildAndPush(ctx context.Context, version, platform, dockerfile string, buildArgs []string, versionRef, latestRef string) error {
135 if _, err := os.Stat(dockerfile); os.IsNotExist(err) {148 if _, err := os.Stat(dockerfile); os.IsNotExist(err) {
136- return fmt.Errorf("Dockerfile not found: %s", dockerfile)149+ return fmt.Errorf("dockerfile not found: %s", dockerfile)
137 }150 }
138 151
139 // Build and load into local daemon (NOT --push).152 // Build and load into local daemon (NOT --push).

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