fix: strip registry domain prefix from image names in routes list
Remove configured registry domain prefix (e.g., 'reg.bnema.dev/') from image names displayed in the routes list for cleaner output. Images from external registries remain unchanged.
- commit
- 8094d0190a82e67cf2570c455bc6dd3207539a44
- author
- brice · · 2026-01-17 14:20 UTC
- parent
- 7db7973
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +77 -0
M internal/usecase/container/service.go +15 -0
| @@ -344,6 +344,8 @@ func (s *Service) ListRoutesWithDetails(ctx context.Context) []domain.RouteInfo | |||
| 344 | 344 | image = labelImage | |
| 345 | 345 | } | |
| 346 | 346 | } | |
| 347 | + | // Strip registry domain prefix from image for cleaner display | |
| 348 | + | image = s.stripRegistryPrefix(image) | |
| 347 | 349 | if networkName, err := s.runtime.GetContainerNetwork(ctx, container.ID); err == nil { | |
| 348 | 350 | network = networkName | |
| 349 | 351 | } | |
| @@ -362,6 +364,19 @@ func (s *Service) ListRoutesWithDetails(ctx context.Context) []domain.RouteInfo | |||
| 362 | 364 | return results | |
| 363 | 365 | } | |
| 364 | 366 | ||
| 367 | + | // stripRegistryPrefix removes the configured registry domain prefix from an image reference. | |
| 368 | + | // For example, "reg.example.com/myapp:latest" becomes "myapp:latest" if registry domain is "reg.example.com". | |
| 369 | + | func (s *Service) stripRegistryPrefix(image string) string { | |
| 370 | + | if s.config.RegistryDomain == "" { | |
| 371 | + | return image | |
| 372 | + | } | |
| 373 | + | prefix := strings.TrimSuffix(s.config.RegistryDomain, "/") + "/" | |
| 374 | + | if strings.HasPrefix(image, prefix) { | |
| 375 | + | return strings.TrimPrefix(image, prefix) | |
| 376 | + | } | |
| 377 | + | return image | |
| 378 | + | } | |
| 379 | + | ||
| 365 | 380 | // ListAttachments returns attachments for a domain. | |
| 366 | 381 | func (s *Service) ListAttachments(ctx context.Context, domainName string) []domain.Attachment { | |
| 367 | 382 | return s.getAttachmentsForDomain(ctx, domainName) | |
| @@ -344,6 +344,8 @@ func (s *Service) ListRoutesWithDetails(ctx context.Context) []domain.RouteInfo | |||||
| 344 | image = labelImage | 344 | image = labelImage | ||
| 345 | } | 345 | } | ||
| 346 | } | 346 | } | ||
| 347 | + | // Strip registry domain prefix from image for cleaner display | |||
| 348 | + | image = s.stripRegistryPrefix(image) | |||
| 347 | if networkName, err := s.runtime.GetContainerNetwork(ctx, container.ID); err == nil { | 349 | if networkName, err := s.runtime.GetContainerNetwork(ctx, container.ID); err == nil { | ||
| 348 | network = networkName | 350 | network = networkName | ||
| 349 | } | 351 | } | ||
| @@ -362,6 +364,19 @@ func (s *Service) ListRoutesWithDetails(ctx context.Context) []domain.RouteInfo | |||||
| 362 | return results | 364 | return results | ||
| 363 | } | 365 | } | ||
| 364 | 366 | ||||
| 367 | + | // stripRegistryPrefix removes the configured registry domain prefix from an image reference. | |||
| 368 | + | // For example, "reg.example.com/myapp:latest" becomes "myapp:latest" if registry domain is "reg.example.com". | |||
| 369 | + | func (s *Service) stripRegistryPrefix(image string) string { | |||
| 370 | + | if s.config.RegistryDomain == "" { | |||
| 371 | + | return image | |||
| 372 | + | } | |||
| 373 | + | prefix := strings.TrimSuffix(s.config.RegistryDomain, "/") + "/" | |||
| 374 | + | if strings.HasPrefix(image, prefix) { | |||
| 375 | + | return strings.TrimPrefix(image, prefix) | |||
| 376 | + | } | |||
| 377 | + | return image | |||
| 378 | + | } | |||
| 379 | + | ||||
| 365 | // ListAttachments returns attachments for a domain. | 380 | // ListAttachments returns attachments for a domain. | ||
| 366 | func (s *Service) ListAttachments(ctx context.Context, domainName string) []domain.Attachment { | 381 | func (s *Service) ListAttachments(ctx context.Context, domainName string) []domain.Attachment { | ||
| 367 | return s.getAttachmentsForDomain(ctx, domainName) | 382 | return s.getAttachmentsForDomain(ctx, domainName) | ||
M internal/usecase/container/service_test.go +62 -0
| @@ -1056,3 +1056,65 @@ func TestService_Deploy_OrphanCleanupRemovesTrueOrphans(t *testing.T) { | |||
| 1056 | 1056 | assert.True(t, exists) | |
| 1057 | 1057 | assert.Equal(t, "new-container", tracked.ID) | |
| 1058 | 1058 | } | |
| 1059 | + | ||
| 1060 | + | func TestService_StripRegistryPrefix(t *testing.T) { | |
| 1061 | + | tests := []struct { | |
| 1062 | + | name string | |
| 1063 | + | registryDomain string | |
| 1064 | + | image string | |
| 1065 | + | expected string | |
| 1066 | + | }{ | |
| 1067 | + | { | |
| 1068 | + | name: "strips registry prefix", | |
| 1069 | + | registryDomain: "reg.example.com", | |
| 1070 | + | image: "reg.example.com/myapp:latest", | |
| 1071 | + | expected: "myapp:latest", | |
| 1072 | + | }, | |
| 1073 | + | { | |
| 1074 | + | name: "strips registry prefix with trailing slash in domain", | |
| 1075 | + | registryDomain: "reg.example.com/", | |
| 1076 | + | image: "reg.example.com/myapp:v1.0", | |
| 1077 | + | expected: "myapp:v1.0", | |
| 1078 | + | }, | |
| 1079 | + | { | |
| 1080 | + | name: "preserves image without registry prefix", | |
| 1081 | + | registryDomain: "reg.example.com", | |
| 1082 | + | image: "nginx:latest", | |
| 1083 | + | expected: "nginx:latest", | |
| 1084 | + | }, | |
| 1085 | + | { | |
| 1086 | + | name: "preserves image with different registry", | |
| 1087 | + | registryDomain: "reg.example.com", | |
| 1088 | + | image: "gcr.io/project/image:latest", | |
| 1089 | + | expected: "gcr.io/project/image:latest", | |
| 1090 | + | }, | |
| 1091 | + | { | |
| 1092 | + | name: "handles empty registry domain", | |
| 1093 | + | registryDomain: "", | |
| 1094 | + | image: "reg.example.com/myapp:latest", | |
| 1095 | + | expected: "reg.example.com/myapp:latest", | |
| 1096 | + | }, | |
| 1097 | + | { | |
| 1098 | + | name: "handles nested paths", | |
| 1099 | + | registryDomain: "reg.example.com", | |
| 1100 | + | image: "reg.example.com/org/repo/app:latest", | |
| 1101 | + | expected: "org/repo/app:latest", | |
| 1102 | + | }, | |
| 1103 | + | } | |
| 1104 | + | ||
| 1105 | + | for _, tt := range tests { | |
| 1106 | + | t.Run(tt.name, func(t *testing.T) { | |
| 1107 | + | runtime := mocks.NewMockContainerRuntime(t) | |
| 1108 | + | envLoader := mocks.NewMockEnvLoader(t) | |
| 1109 | + | eventBus := mocks.NewMockEventPublisher(t) | |
| 1110 | + | ||
| 1111 | + | config := Config{ | |
| 1112 | + | RegistryDomain: tt.registryDomain, | |
| 1113 | + | } | |
| 1114 | + | svc := NewService(runtime, envLoader, eventBus, nil, config) | |
| 1115 | + | ||
| 1116 | + | result := svc.stripRegistryPrefix(tt.image) | |
| 1117 | + | assert.Equal(t, tt.expected, result) | |
| 1118 | + | }) | |
| 1119 | + | } | |
| 1120 | + | } | |
| @@ -1056,3 +1056,65 @@ func TestService_Deploy_OrphanCleanupRemovesTrueOrphans(t *testing.T) { | |||||
| 1056 | assert.True(t, exists) | 1056 | assert.True(t, exists) | ||
| 1057 | assert.Equal(t, "new-container", tracked.ID) | 1057 | assert.Equal(t, "new-container", tracked.ID) | ||
| 1058 | } | 1058 | } | ||
| 1059 | + | ||||
| 1060 | + | func TestService_StripRegistryPrefix(t *testing.T) { | |||
| 1061 | + | tests := []struct { | |||
| 1062 | + | name string | |||
| 1063 | + | registryDomain string | |||
| 1064 | + | image string | |||
| 1065 | + | expected string | |||
| 1066 | + | }{ | |||
| 1067 | + | { | |||
| 1068 | + | name: "strips registry prefix", | |||
| 1069 | + | registryDomain: "reg.example.com", | |||
| 1070 | + | image: "reg.example.com/myapp:latest", | |||
| 1071 | + | expected: "myapp:latest", | |||
| 1072 | + | }, | |||
| 1073 | + | { | |||
| 1074 | + | name: "strips registry prefix with trailing slash in domain", | |||
| 1075 | + | registryDomain: "reg.example.com/", | |||
| 1076 | + | image: "reg.example.com/myapp:v1.0", | |||
| 1077 | + | expected: "myapp:v1.0", | |||
| 1078 | + | }, | |||
| 1079 | + | { | |||
| 1080 | + | name: "preserves image without registry prefix", | |||
| 1081 | + | registryDomain: "reg.example.com", | |||
| 1082 | + | image: "nginx:latest", | |||
| 1083 | + | expected: "nginx:latest", | |||
| 1084 | + | }, | |||
| 1085 | + | { | |||
| 1086 | + | name: "preserves image with different registry", | |||
| 1087 | + | registryDomain: "reg.example.com", | |||
| 1088 | + | image: "gcr.io/project/image:latest", | |||
| 1089 | + | expected: "gcr.io/project/image:latest", | |||
| 1090 | + | }, | |||
| 1091 | + | { | |||
| 1092 | + | name: "handles empty registry domain", | |||
| 1093 | + | registryDomain: "", | |||
| 1094 | + | image: "reg.example.com/myapp:latest", | |||
| 1095 | + | expected: "reg.example.com/myapp:latest", | |||
| 1096 | + | }, | |||
| 1097 | + | { | |||
| 1098 | + | name: "handles nested paths", | |||
| 1099 | + | registryDomain: "reg.example.com", | |||
| 1100 | + | image: "reg.example.com/org/repo/app:latest", | |||
| 1101 | + | expected: "org/repo/app:latest", | |||
| 1102 | + | }, | |||
| 1103 | + | } | |||
| 1104 | + | ||||
| 1105 | + | for _, tt := range tests { | |||
| 1106 | + | t.Run(tt.name, func(t *testing.T) { | |||
| 1107 | + | runtime := mocks.NewMockContainerRuntime(t) | |||
| 1108 | + | envLoader := mocks.NewMockEnvLoader(t) | |||
| 1109 | + | eventBus := mocks.NewMockEventPublisher(t) | |||
| 1110 | + | ||||
| 1111 | + | config := Config{ | |||
| 1112 | + | RegistryDomain: tt.registryDomain, | |||
| 1113 | + | } | |||
| 1114 | + | svc := NewService(runtime, envLoader, eventBus, nil, config) | |||
| 1115 | + | ||||
| 1116 | + | result := svc.stripRegistryPrefix(tt.image) | |||
| 1117 | + | assert.Equal(t, tt.expected, result) | |||
| 1118 | + | }) | |||
| 1119 | + | } | |||
| 1120 | + | } | |||