refactor(cli): deduplicate deploy failure and remote helpers
- commit
- a8338c05c00bd374a38d162d052501e768ddfd0a
- author
- brice · · 2026-04-08 14:57 UTC
- parent
- 4162c86
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
7 files · +42 -31
M internal/adapters/in/cli/auth.go +24 -15
| @@ -232,6 +232,15 @@ Examples: | |||
| 232 | 232 | return cmd | |
| 233 | 233 | } | |
| 234 | 234 | ||
| 235 | + | func resolveRequiredRemote(flagToken string) (*remote.ResolvedRemote, error) { | |
| 236 | + | resolved, isRemote := remote.Resolve(remoteFlag, flagToken, insecureTLSFlag) | |
| 237 | + | if !isRemote { | |
| 238 | + | return nil, fmt.Errorf("no remote specified. Use --remote or 'gordon remotes use <name>'") | |
| 239 | + | } | |
| 240 | + | ||
| 241 | + | return resolved, nil | |
| 242 | + | } | |
| 243 | + | ||
| 235 | 244 | func runAuthLoginWithToken(ctx context.Context, token string, out io.Writer) error { | |
| 236 | 245 | token = strings.TrimSpace(token) | |
| 237 | 246 | if token == "" { | |
| @@ -239,9 +248,9 @@ func runAuthLoginWithToken(ctx context.Context, token string, out io.Writer) err | |||
| 239 | 248 | } | |
| 240 | 249 | ||
| 241 | 250 | // Resolve remote — but use the new token (not the stored one) for verification. | |
| 242 | - | resolved, isRemote := remote.Resolve(remoteFlag, "", insecureTLSFlag) | |
| 243 | - | if !isRemote { | |
| 244 | - | return fmt.Errorf("no remote specified. Use --remote or 'gordon remotes use <name>'") | |
| 251 | + | resolved, err := resolveRequiredRemote("") | |
| 252 | + | if err != nil { | |
| 253 | + | return err | |
| 245 | 254 | } | |
| 246 | 255 | ||
| 247 | 256 | client := remote.NewClient(resolved.URL, remoteClientOptions(token, resolved.InsecureTLS)...) | |
| @@ -271,9 +280,9 @@ func runAuthLoginWithToken(ctx context.Context, token string, out io.Writer) err | |||
| 271 | 280 | } | |
| 272 | 281 | ||
| 273 | 282 | func runAuthLoginVerify(ctx context.Context, out io.Writer) error { | |
| 274 | - | resolved, isRemote := remote.Resolve(remoteFlag, tokenFlag, insecureTLSFlag) | |
| 275 | - | if !isRemote { | |
| 276 | - | return fmt.Errorf("no remote specified. Use --remote or 'gordon remotes use <name>'") | |
| 283 | + | resolved, err := resolveRequiredRemote(tokenFlag) | |
| 284 | + | if err != nil { | |
| 285 | + | return err | |
| 277 | 286 | } | |
| 278 | 287 | if resolved.Token == "" { | |
| 279 | 288 | return fmt.Errorf("no token stored for remote '%s'; use: gordon auth login --token <token>", resolved.DisplayName()) | |
| @@ -317,9 +326,9 @@ Examples: | |||
| 317 | 326 | } | |
| 318 | 327 | ||
| 319 | 328 | func runAuthShowToken(out io.Writer) error { | |
| 320 | - | resolved, isRemote := remote.Resolve(remoteFlag, tokenFlag, insecureTLSFlag) | |
| 321 | - | if !isRemote { | |
| 322 | - | return fmt.Errorf("no remote specified. Use --remote or 'gordon remotes use <name>'") | |
| 329 | + | resolved, err := resolveRequiredRemote(tokenFlag) | |
| 330 | + | if err != nil { | |
| 331 | + | return err | |
| 323 | 332 | } | |
| 324 | 333 | if resolved.Token == "" { | |
| 325 | 334 | return fmt.Errorf("no token found for remote '%s'", resolved.DisplayName()) | |
| @@ -355,9 +364,9 @@ Examples: | |||
| 355 | 364 | } | |
| 356 | 365 | ||
| 357 | 366 | func runAuthLogout(out io.Writer) error { | |
| 358 | - | resolved, isRemote := remote.Resolve(remoteFlag, tokenFlag, insecureTLSFlag) | |
| 359 | - | if !isRemote { | |
| 360 | - | return fmt.Errorf("no remote specified. Use --remote or 'gordon remotes use <name>'") | |
| 367 | + | resolved, err := resolveRequiredRemote(tokenFlag) | |
| 368 | + | if err != nil { | |
| 369 | + | return err | |
| 361 | 370 | } | |
| 362 | 371 | if resolved.Name == "" { | |
| 363 | 372 | return fmt.Errorf("cannot logout from ad-hoc URL. Use 'gordon remotes add' to save this remote first") | |
| @@ -700,9 +709,9 @@ Examples: | |||
| 700 | 709 | ||
| 701 | 710 | // runAuthStatus checks authentication status for the active remote. | |
| 702 | 711 | func runAuthStatus(ctx context.Context) error { | |
| 703 | - | resolved, isRemote := remote.Resolve(remoteFlag, tokenFlag, insecureTLSFlag) | |
| 704 | - | if !isRemote { | |
| 705 | - | return fmt.Errorf("no remote specified. Use --remote or 'gordon remotes use <name>'") | |
| 712 | + | resolved, err := resolveRequiredRemote(tokenFlag) | |
| 713 | + | if err != nil { | |
| 714 | + | return err | |
| 706 | 715 | } | |
| 707 | 716 | ||
| 708 | 717 | client := remote.NewClient(resolved.URL, remoteClientOptions(resolved.Token, resolved.InsecureTLS)...) | |
| @@ -232,6 +232,15 @@ Examples: | |||||
| 232 | return cmd | 232 | return cmd | ||
| 233 | } | 233 | } | ||
| 234 | 234 | ||||
| 235 | + | func resolveRequiredRemote(flagToken string) (*remote.ResolvedRemote, error) { | |||
| 236 | + | resolved, isRemote := remote.Resolve(remoteFlag, flagToken, insecureTLSFlag) | |||
| 237 | + | if !isRemote { | |||
| 238 | + | return nil, fmt.Errorf("no remote specified. Use --remote or 'gordon remotes use <name>'") | |||
| 239 | + | } | |||
| 240 | + | ||||
| 241 | + | return resolved, nil | |||
| 242 | + | } | |||
| 243 | + | ||||
| 235 | func runAuthLoginWithToken(ctx context.Context, token string, out io.Writer) error { | 244 | func runAuthLoginWithToken(ctx context.Context, token string, out io.Writer) error { | ||
| 236 | token = strings.TrimSpace(token) | 245 | token = strings.TrimSpace(token) | ||
| 237 | if token == "" { | 246 | if token == "" { | ||
| @@ -239,9 +248,9 @@ func runAuthLoginWithToken(ctx context.Context, token string, out io.Writer) err | |||||
| 239 | } | 248 | } | ||
| 240 | 249 | ||||
| 241 | // Resolve remote — but use the new token (not the stored one) for verification. | 250 | // Resolve remote — but use the new token (not the stored one) for verification. | ||
| 242 | - | resolved, isRemote := remote.Resolve(remoteFlag, "", insecureTLSFlag) | 251 | + | resolved, err := resolveRequiredRemote("") |
| 243 | - | if !isRemote { | 252 | + | if err != nil { |
| 244 | - | return fmt.Errorf("no remote specified. Use --remote or 'gordon remotes use <name>'") | 253 | + | return err |
| 245 | } | 254 | } | ||
| 246 | 255 | ||||
| 247 | client := remote.NewClient(resolved.URL, remoteClientOptions(token, resolved.InsecureTLS)...) | 256 | client := remote.NewClient(resolved.URL, remoteClientOptions(token, resolved.InsecureTLS)...) | ||
| @@ -271,9 +280,9 @@ func runAuthLoginWithToken(ctx context.Context, token string, out io.Writer) err | |||||
| 271 | } | 280 | } | ||
| 272 | 281 | ||||
| 273 | func runAuthLoginVerify(ctx context.Context, out io.Writer) error { | 282 | func runAuthLoginVerify(ctx context.Context, out io.Writer) error { | ||
| 274 | - | resolved, isRemote := remote.Resolve(remoteFlag, tokenFlag, insecureTLSFlag) | 283 | + | resolved, err := resolveRequiredRemote(tokenFlag) |
| 275 | - | if !isRemote { | 284 | + | if err != nil { |
| 276 | - | return fmt.Errorf("no remote specified. Use --remote or 'gordon remotes use <name>'") | 285 | + | return err |
| 277 | } | 286 | } | ||
| 278 | if resolved.Token == "" { | 287 | if resolved.Token == "" { | ||
| 279 | return fmt.Errorf("no token stored for remote '%s'; use: gordon auth login --token <token>", resolved.DisplayName()) | 288 | return fmt.Errorf("no token stored for remote '%s'; use: gordon auth login --token <token>", resolved.DisplayName()) | ||
| @@ -317,9 +326,9 @@ Examples: | |||||
| 317 | } | 326 | } | ||
| 318 | 327 | ||||
| 319 | func runAuthShowToken(out io.Writer) error { | 328 | func runAuthShowToken(out io.Writer) error { | ||
| 320 | - | resolved, isRemote := remote.Resolve(remoteFlag, tokenFlag, insecureTLSFlag) | 329 | + | resolved, err := resolveRequiredRemote(tokenFlag) |
| 321 | - | if !isRemote { | 330 | + | if err != nil { |
| 322 | - | return fmt.Errorf("no remote specified. Use --remote or 'gordon remotes use <name>'") | 331 | + | return err |
| 323 | } | 332 | } | ||
| 324 | if resolved.Token == "" { | 333 | if resolved.Token == "" { | ||
| 325 | return fmt.Errorf("no token found for remote '%s'", resolved.DisplayName()) | 334 | return fmt.Errorf("no token found for remote '%s'", resolved.DisplayName()) | ||
| @@ -355,9 +364,9 @@ Examples: | |||||
| 355 | } | 364 | } | ||
| 356 | 365 | ||||
| 357 | func runAuthLogout(out io.Writer) error { | 366 | func runAuthLogout(out io.Writer) error { | ||
| 358 | - | resolved, isRemote := remote.Resolve(remoteFlag, tokenFlag, insecureTLSFlag) | 367 | + | resolved, err := resolveRequiredRemote(tokenFlag) |
| 359 | - | if !isRemote { | 368 | + | if err != nil { |
| 360 | - | return fmt.Errorf("no remote specified. Use --remote or 'gordon remotes use <name>'") | 369 | + | return err |
| 361 | } | 370 | } | ||
| 362 | if resolved.Name == "" { | 371 | if resolved.Name == "" { | ||
| 363 | return fmt.Errorf("cannot logout from ad-hoc URL. Use 'gordon remotes add' to save this remote first") | 372 | return fmt.Errorf("cannot logout from ad-hoc URL. Use 'gordon remotes add' to save this remote first") | ||
| @@ -700,9 +709,9 @@ Examples: | |||||
| 700 | 709 | ||||
| 701 | // runAuthStatus checks authentication status for the active remote. | 710 | // runAuthStatus checks authentication status for the active remote. | ||
| 702 | func runAuthStatus(ctx context.Context) error { | 711 | func runAuthStatus(ctx context.Context) error { | ||
| 703 | - | resolved, isRemote := remote.Resolve(remoteFlag, tokenFlag, insecureTLSFlag) | 712 | + | resolved, err := resolveRequiredRemote(tokenFlag) |
| 704 | - | if !isRemote { | 713 | + | if err != nil { |
| 705 | - | return fmt.Errorf("no remote specified. Use --remote or 'gordon remotes use <name>'") | 714 | + | return err |
| 706 | } | 715 | } | ||
| 707 | 716 | ||||
| 708 | client := remote.NewClient(resolved.URL, remoteClientOptions(resolved.Token, resolved.InsecureTLS)...) | 717 | client := remote.NewClient(resolved.URL, remoteClientOptions(resolved.Token, resolved.InsecureTLS)...) | ||
M internal/adapters/in/cli/deploy.go +1 -4
| @@ -71,10 +71,7 @@ func runDeploy(ctx context.Context, deployer deployer, isRemote bool, deployDoma | |||
| 71 | 71 | messageDomain = result.Domain | |
| 72 | 72 | } | |
| 73 | 73 | ||
| 74 | - | containerID := result.ContainerID | |
| 75 | - | if containerID != "" && len(containerID) > 12 { | |
| 76 | - | containerID = containerID[:12] | |
| 77 | - | } | |
| 74 | + | containerID := shortContainerID(result.ContainerID) | |
| 78 | 75 | ||
| 79 | 76 | switch result.Status { | |
| 80 | 77 | case "deployed": | |
| @@ -71,10 +71,7 @@ func runDeploy(ctx context.Context, deployer deployer, isRemote bool, deployDoma | |||||
| 71 | messageDomain = result.Domain | 71 | messageDomain = result.Domain | ||
| 72 | } | 72 | } | ||
| 73 | 73 | ||||
| 74 | - | containerID := result.ContainerID | 74 | + | containerID := shortContainerID(result.ContainerID) |
| 75 | - | if containerID != "" && len(containerID) > 12 { | |||
| 76 | - | containerID = containerID[:12] | |||
| 77 | - | } | |||
| 78 | 75 | ||||
| 79 | switch result.Status { | 76 | switch result.Status { | ||
| 80 | case "deployed": | 77 | case "deployed": | ||
M internal/adapters/in/cli/deploy_error.go +4 -3
| @@ -56,14 +56,15 @@ func structuredDeployFailure(err error) (error, bool) { | |||
| 56 | 56 | ||
| 57 | 57 | func renderDeployFailure(summary, cause, hint string, logs []string) string { | |
| 58 | 58 | if summary == "" { | |
| 59 | - | summary = "failed to deploy" | |
| 59 | + | summary = domain.DefaultDeployFailureSummary | |
| 60 | 60 | } | |
| 61 | 61 | ||
| 62 | 62 | var b strings.Builder | |
| 63 | - | if summary == "failed to deploy" { | |
| 63 | + | if summary == domain.DefaultDeployFailureSummary { | |
| 64 | 64 | b.WriteString(summary) | |
| 65 | 65 | } else { | |
| 66 | - | b.WriteString("failed to deploy: ") | |
| 66 | + | b.WriteString(domain.DefaultDeployFailureSummary) | |
| 67 | + | b.WriteString(": ") | |
| 67 | 68 | b.WriteString(summary) | |
| 68 | 69 | } | |
| 69 | 70 | ||
| @@ -56,14 +56,15 @@ func structuredDeployFailure(err error) (error, bool) { | |||||
| 56 | 56 | ||||
| 57 | func renderDeployFailure(summary, cause, hint string, logs []string) string { | 57 | func renderDeployFailure(summary, cause, hint string, logs []string) string { | ||
| 58 | if summary == "" { | 58 | if summary == "" { | ||
| 59 | - | summary = "failed to deploy" | 59 | + | summary = domain.DefaultDeployFailureSummary |
| 60 | } | 60 | } | ||
| 61 | 61 | ||||
| 62 | var b strings.Builder | 62 | var b strings.Builder | ||
| 63 | - | if summary == "failed to deploy" { | 63 | + | if summary == domain.DefaultDeployFailureSummary { |
| 64 | b.WriteString(summary) | 64 | b.WriteString(summary) | ||
| 65 | } else { | 65 | } else { | ||
| 66 | - | b.WriteString("failed to deploy: ") | 66 | + | b.WriteString(domain.DefaultDeployFailureSummary) |
| 67 | + | b.WriteString(": ") | |||
| 67 | b.WriteString(summary) | 68 | b.WriteString(summary) | ||
| 68 | } | 69 | } | ||
| 69 | 70 | ||||
M internal/adapters/in/cli/presentation.go +8 -0
| @@ -63,3 +63,11 @@ func cliRenderWarning(msg string) string { | |||
| 63 | 63 | func cliRenderInfo(msg string) string { | |
| 64 | 64 | return styles.RenderInfo(msg) | |
| 65 | 65 | } | |
| 66 | + | ||
| 67 | + | func shortContainerID(id string) string { | |
| 68 | + | if len(id) > 12 { | |
| 69 | + | return id[:12] | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | return id | |
| 73 | + | } | |
| @@ -63,3 +63,11 @@ func cliRenderWarning(msg string) string { | |||||
| 63 | func cliRenderInfo(msg string) string { | 63 | func cliRenderInfo(msg string) string { | ||
| 64 | return styles.RenderInfo(msg) | 64 | return styles.RenderInfo(msg) | ||
| 65 | } | 65 | } | ||
| 66 | + | ||||
| 67 | + | func shortContainerID(id string) string { | |||
| 68 | + | if len(id) > 12 { | |||
| 69 | + | return id[:12] | |||
| 70 | + | } | |||
| 71 | + | ||||
| 72 | + | return id | |||
| 73 | + | } | |||
M internal/adapters/in/cli/push.go +1 -4
| @@ -681,10 +681,7 @@ func deployAfterPush(ctx context.Context, cp ControlPlane, pushDomain string, no | |||
| 681 | 681 | if err != nil { | |
| 682 | 682 | return formatDeployFailure(err) | |
| 683 | 683 | } | |
| 684 | - | containerID := result.ContainerID | |
| 685 | - | if len(containerID) > 12 { | |
| 686 | - | containerID = containerID[:12] | |
| 687 | - | } | |
| 684 | + | containerID := shortContainerID(result.ContainerID) | |
| 688 | 685 | fmt.Println(styles.RenderSuccess(fmt.Sprintf("Deployed %s (container: %s)", pushDomain, containerID))) | |
| 689 | 686 | return nil | |
| 690 | 687 | } | |
| @@ -681,10 +681,7 @@ func deployAfterPush(ctx context.Context, cp ControlPlane, pushDomain string, no | |||||
| 681 | if err != nil { | 681 | if err != nil { | ||
| 682 | return formatDeployFailure(err) | 682 | return formatDeployFailure(err) | ||
| 683 | } | 683 | } | ||
| 684 | - | containerID := result.ContainerID | 684 | + | containerID := shortContainerID(result.ContainerID) |
| 685 | - | if len(containerID) > 12 { | |||
| 686 | - | containerID = containerID[:12] | |||
| 687 | - | } | |||
| 688 | fmt.Println(styles.RenderSuccess(fmt.Sprintf("Deployed %s (container: %s)", pushDomain, containerID))) | 685 | fmt.Println(styles.RenderSuccess(fmt.Sprintf("Deployed %s (container: %s)", pushDomain, containerID))) | ||
| 689 | return nil | 686 | return nil | ||
| 690 | } | 687 | } | ||
M internal/adapters/in/cli/rollback.go +1 -4
| @@ -244,10 +244,7 @@ func deploySelectedTag(ctx context.Context, cp ControlPlane, route *domain.Route | |||
| 244 | 244 | } | |
| 245 | 245 | return fmt.Errorf("failed to deploy (route reverted): %w", err) | |
| 246 | 246 | } | |
| 247 | - | containerID := result.ContainerID | |
| 248 | - | if len(containerID) > 12 { | |
| 249 | - | containerID = containerID[:12] | |
| 250 | - | } | |
| 247 | + | containerID := shortContainerID(result.ContainerID) | |
| 251 | 248 | fmt.Println(styles.RenderSuccess(fmt.Sprintf("Rolled back %s to %s (container: %s)", rollbackDomain, selectedTag, containerID))) | |
| 252 | 249 | return nil | |
| 253 | 250 | } | |
| @@ -244,10 +244,7 @@ func deploySelectedTag(ctx context.Context, cp ControlPlane, route *domain.Route | |||||
| 244 | } | 244 | } | ||
| 245 | return fmt.Errorf("failed to deploy (route reverted): %w", err) | 245 | return fmt.Errorf("failed to deploy (route reverted): %w", err) | ||
| 246 | } | 246 | } | ||
| 247 | - | containerID := result.ContainerID | 247 | + | containerID := shortContainerID(result.ContainerID) |
| 248 | - | if len(containerID) > 12 { | |||
| 249 | - | containerID = containerID[:12] | |||
| 250 | - | } | |||
| 251 | fmt.Println(styles.RenderSuccess(fmt.Sprintf("Rolled back %s to %s (container: %s)", rollbackDomain, selectedTag, containerID))) | 248 | fmt.Println(styles.RenderSuccess(fmt.Sprintf("Rolled back %s to %s (container: %s)", rollbackDomain, selectedTag, containerID))) | ||
| 252 | return nil | 249 | return nil | ||
| 253 | } | 250 | } | ||
M internal/domain/deploy_failure.go +3 -1
| @@ -1,5 +1,7 @@ | |||
| 1 | 1 | package domain | |
| 2 | 2 | ||
| 3 | + | const DefaultDeployFailureSummary = "failed to deploy" | |
| 4 | + | ||
| 3 | 5 | // DeployFailureError describes a surfaced deployment failure. | |
| 4 | 6 | type DeployFailureError struct { | |
| 5 | 7 | Summary string | |
| @@ -14,7 +16,7 @@ type DeployFailureError struct { | |||
| 14 | 16 | // Error returns the deploy failure summary. | |
| 15 | 17 | func (e *DeployFailureError) Error() string { | |
| 16 | 18 | if e == nil || e.Summary == "" { | |
| 17 | - | return "failed to deploy" | |
| 19 | + | return DefaultDeployFailureSummary | |
| 18 | 20 | } | |
| 19 | 21 | ||
| 20 | 22 | return e.Summary | |
| @@ -1,5 +1,7 @@ | |||||
| 1 | package domain | 1 | package domain | ||
| 2 | 2 | ||||
| 3 | + | const DefaultDeployFailureSummary = "failed to deploy" | |||
| 4 | + | ||||
| 3 | // DeployFailureError describes a surfaced deployment failure. | 5 | // DeployFailureError describes a surfaced deployment failure. | ||
| 4 | type DeployFailureError struct { | 6 | type DeployFailureError struct { | ||
| 5 | Summary string | 7 | Summary string | ||
| @@ -14,7 +16,7 @@ type DeployFailureError struct { | |||||
| 14 | // Error returns the deploy failure summary. | 16 | // Error returns the deploy failure summary. | ||
| 15 | func (e *DeployFailureError) Error() string { | 17 | func (e *DeployFailureError) Error() string { | ||
| 16 | if e == nil || e.Summary == "" { | 18 | if e == nil || e.Summary == "" { | ||
| 17 | - | return "failed to deploy" | 19 | + | return DefaultDeployFailureSummary |
| 18 | } | 20 | } | ||
| 19 | 21 | ||||
| 20 | return e.Summary | 22 | return e.Summary | ||