detached 0453d8d

refactor(pkg): update manifest package and dependencies for clean architecture

- Update go.mod dependencies for mockery and testing
- Refactor manifest annotations and types packages
- Update test utilities for new architecture
commit
0453d8d356730b7136c77ae7a206df2b428c0264
author
brice · · 2026-01-12 17:05 UTC
committer
brice · · 2026-01-12 19:09 UTC
parent
51f38f9
signature
unsigned
8 files · +154 -152
M go.mod +26 -23
@@ -1,18 +1,24 @@
11 module gordon
22
3-go 1.24.3
3+go 1.25.5
44
55 require (
6+ github.com/bnema/zerowrap v1.3.0
67 github.com/docker/docker v28.3.3+incompatible
78 github.com/docker/go-connections v0.5.0
89 github.com/google/uuid v1.6.0
910 github.com/rs/zerolog v1.34.0
10- github.com/spf13/cobra v1.9.1
11- github.com/spf13/viper v1.20.1
12- github.com/stretchr/testify v1.10.0
11+ github.com/spf13/cobra v1.10.2
12+ github.com/spf13/viper v1.21.0
13+ github.com/stretchr/testify v1.11.1
1314 gopkg.in/natefinch/lumberjack.v2 v2.2.1
1415 )
1516
17+require (
18+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
19+ go.yaml.in/yaml/v3 v3.0.4 // indirect
20+)
21+
1622 require (
1723 github.com/davecgh/go-spew v1.1.1 // indirect
1824 github.com/pmezard/go-difflib v1.0.0 // indirect
@@ -29,39 +35,36 @@ require (
2935 github.com/distribution/reference v0.6.0 // indirect
3036 github.com/docker/go-units v0.5.0 // indirect
3137 github.com/felixge/httpsnoop v1.0.4 // indirect
32- github.com/fsnotify/fsnotify v1.8.0 // direct
33- github.com/go-logr/logr v1.4.2 // indirect
38+ github.com/fsnotify/fsnotify v1.9.0 // direct
39+ github.com/go-logr/logr v1.4.3 // indirect
3440 github.com/go-logr/stdr v1.2.2 // indirect
35- github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
41+ github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
3642 github.com/gogo/protobuf v1.3.2 // indirect
3743 github.com/inconshreveable/mousetrap v1.1.0 // indirect
38- github.com/mattn/go-colorable v0.1.13 // indirect
39- github.com/mattn/go-isatty v0.0.19 // indirect
44+ github.com/mattn/go-colorable v0.1.14 // indirect
45+ github.com/mattn/go-isatty v0.0.20 // indirect
4046 github.com/moby/docker-image-spec v1.3.1 // indirect
4147 github.com/moby/sys/atomicwriter v0.1.0 // indirect
4248 github.com/moby/term v0.5.2 // indirect
4349 github.com/morikuni/aec v1.0.0 // indirect
4450 github.com/opencontainers/go-digest v1.0.0 // indirect
4551 github.com/opencontainers/image-spec v1.1.1 // indirect
46- github.com/pelletier/go-toml/v2 v2.2.3 // indirect
52+ github.com/pelletier/go-toml/v2 v2.2.4 // indirect
4753 github.com/pkg/errors v0.9.1 // indirect
48- github.com/sagikazarmark/locafero v0.7.0 // indirect
49- github.com/sourcegraph/conc v0.3.0 // indirect
50- github.com/spf13/afero v1.14.0
51- github.com/spf13/cast v1.7.1 // indirect
52- github.com/spf13/pflag v1.0.6 // indirect
54+ github.com/sagikazarmark/locafero v0.12.0 // indirect
55+ github.com/spf13/afero v1.15.0
56+ github.com/spf13/cast v1.10.0 // indirect
57+ github.com/spf13/pflag v1.0.10 // indirect
5358 github.com/subosito/gotenv v1.6.0 // indirect
54- go.opentelemetry.io/auto/sdk v1.1.0 // indirect
59+ go.opentelemetry.io/auto/sdk v1.2.1 // indirect
5560 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
56- go.opentelemetry.io/otel v1.36.0 // indirect
61+ go.opentelemetry.io/otel v1.39.0 // indirect
5762 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 // indirect
58- go.opentelemetry.io/otel/metric v1.36.0 // indirect
63+ go.opentelemetry.io/otel/metric v1.39.0 // indirect
5964 go.opentelemetry.io/otel/sdk v1.36.0 // indirect
60- go.opentelemetry.io/otel/trace v1.36.0 // indirect
61- go.uber.org/atomic v1.9.0 // indirect
62- go.uber.org/multierr v1.9.0 // indirect
63- golang.org/x/sys v0.33.0 // indirect
64- golang.org/x/text v0.26.0 // indirect
65+ go.opentelemetry.io/otel/trace v1.39.0 // indirect
66+ golang.org/x/sys v0.40.0 // indirect
67+ golang.org/x/text v0.33.0 // indirect
6568 gopkg.in/yaml.v3 v3.0.1 // indirect
6669 gotest.tools/v3 v3.5.2 // indirect
6770 )
@@ -1,18 +1,24 @@
1 module gordon1 module gordon
2 2
3-go 1.24.33+go 1.25.5
4 4
5 require (5 require (
6+ github.com/bnema/zerowrap v1.3.0
6 github.com/docker/docker v28.3.3+incompatible7 github.com/docker/docker v28.3.3+incompatible
7 github.com/docker/go-connections v0.5.08 github.com/docker/go-connections v0.5.0
8 github.com/google/uuid v1.6.09 github.com/google/uuid v1.6.0
9 github.com/rs/zerolog v1.34.010 github.com/rs/zerolog v1.34.0
10- github.com/spf13/cobra v1.9.111+ github.com/spf13/cobra v1.10.2
11- github.com/spf13/viper v1.20.112+ github.com/spf13/viper v1.21.0
12- github.com/stretchr/testify v1.10.013+ github.com/stretchr/testify v1.11.1
13 gopkg.in/natefinch/lumberjack.v2 v2.2.114 gopkg.in/natefinch/lumberjack.v2 v2.2.1
14 )15 )
15 16
17+require (
18+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
19+ go.yaml.in/yaml/v3 v3.0.4 // indirect
20+)
21+
16 require (22 require (
17 github.com/davecgh/go-spew v1.1.1 // indirect23 github.com/davecgh/go-spew v1.1.1 // indirect
18 github.com/pmezard/go-difflib v1.0.0 // indirect24 github.com/pmezard/go-difflib v1.0.0 // indirect
@@ -29,39 +35,36 @@ require (
29 github.com/distribution/reference v0.6.0 // indirect35 github.com/distribution/reference v0.6.0 // indirect
30 github.com/docker/go-units v0.5.0 // indirect36 github.com/docker/go-units v0.5.0 // indirect
31 github.com/felixge/httpsnoop v1.0.4 // indirect37 github.com/felixge/httpsnoop v1.0.4 // indirect
32- github.com/fsnotify/fsnotify v1.8.0 // direct38+ github.com/fsnotify/fsnotify v1.9.0 // direct
33- github.com/go-logr/logr v1.4.2 // indirect39+ github.com/go-logr/logr v1.4.3 // indirect
34 github.com/go-logr/stdr v1.2.2 // indirect40 github.com/go-logr/stdr v1.2.2 // indirect
35- github.com/go-viper/mapstructure/v2 v2.4.0 // indirect41+ github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
36 github.com/gogo/protobuf v1.3.2 // indirect42 github.com/gogo/protobuf v1.3.2 // indirect
37 github.com/inconshreveable/mousetrap v1.1.0 // indirect43 github.com/inconshreveable/mousetrap v1.1.0 // indirect
38- github.com/mattn/go-colorable v0.1.13 // indirect44+ github.com/mattn/go-colorable v0.1.14 // indirect
39- github.com/mattn/go-isatty v0.0.19 // indirect45+ github.com/mattn/go-isatty v0.0.20 // indirect
40 github.com/moby/docker-image-spec v1.3.1 // indirect46 github.com/moby/docker-image-spec v1.3.1 // indirect
41 github.com/moby/sys/atomicwriter v0.1.0 // indirect47 github.com/moby/sys/atomicwriter v0.1.0 // indirect
42 github.com/moby/term v0.5.2 // indirect48 github.com/moby/term v0.5.2 // indirect
43 github.com/morikuni/aec v1.0.0 // indirect49 github.com/morikuni/aec v1.0.0 // indirect
44 github.com/opencontainers/go-digest v1.0.0 // indirect50 github.com/opencontainers/go-digest v1.0.0 // indirect
45 github.com/opencontainers/image-spec v1.1.1 // indirect51 github.com/opencontainers/image-spec v1.1.1 // indirect
46- github.com/pelletier/go-toml/v2 v2.2.3 // indirect52+ github.com/pelletier/go-toml/v2 v2.2.4 // indirect
47 github.com/pkg/errors v0.9.1 // indirect53 github.com/pkg/errors v0.9.1 // indirect
48- github.com/sagikazarmark/locafero v0.7.0 // indirect54+ github.com/sagikazarmark/locafero v0.12.0 // indirect
49- github.com/sourcegraph/conc v0.3.0 // indirect55+ github.com/spf13/afero v1.15.0
50- github.com/spf13/afero v1.14.056+ github.com/spf13/cast v1.10.0 // indirect
51- github.com/spf13/cast v1.7.1 // indirect57+ github.com/spf13/pflag v1.0.10 // indirect
52- github.com/spf13/pflag v1.0.6 // indirect
53 github.com/subosito/gotenv v1.6.0 // indirect58 github.com/subosito/gotenv v1.6.0 // indirect
54- go.opentelemetry.io/auto/sdk v1.1.0 // indirect59+ go.opentelemetry.io/auto/sdk v1.2.1 // indirect
55 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect60 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
56- go.opentelemetry.io/otel v1.36.0 // indirect61+ go.opentelemetry.io/otel v1.39.0 // indirect
57 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 // indirect62 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 // indirect
58- go.opentelemetry.io/otel/metric v1.36.0 // indirect63+ go.opentelemetry.io/otel/metric v1.39.0 // indirect
59 go.opentelemetry.io/otel/sdk v1.36.0 // indirect64 go.opentelemetry.io/otel/sdk v1.36.0 // indirect
60- go.opentelemetry.io/otel/trace v1.36.0 // indirect65+ go.opentelemetry.io/otel/trace v1.39.0 // indirect
61- go.uber.org/atomic v1.9.0 // indirect66+ golang.org/x/sys v0.40.0 // indirect
62- go.uber.org/multierr v1.9.0 // indirect67+ golang.org/x/text v0.33.0 // indirect
63- golang.org/x/sys v0.33.0 // indirect
64- golang.org/x/text v0.26.0 // indirect
65 gopkg.in/yaml.v3 v3.0.1 // indirect68 gopkg.in/yaml.v3 v3.0.1 // indirect
66 gotest.tools/v3 v3.5.2 // indirect69 gotest.tools/v3 v3.5.2 // indirect
67 )70 )
M go.sum +47 -47 generated file: collapsed
M internal/testutils/helpers.go +1 -1
@@ -80,4 +80,4 @@ port = 8080`
8080 default:
8181 return content
8282 }
83-}⏎̸
83+}
@@ -80,4 +80,4 @@ port = 8080`
80 default:80 default:
81 return content81 return content
82 }82 }
83-}⏎̸83+}
M pkg/manifest/annotations.go +6 -7
@@ -14,7 +14,7 @@ func ParseManifestAnnotations(manifestData []byte, contentType string) (map[stri
1414 // Docker v2.2 manifests don't support annotations at manifest level
1515 return map[string]string{}, nil
1616 case "application/vnd.oci.image.index.v1+json",
17- "application/vnd.docker.distribution.manifest.list.v2+json":
17+ "application/vnd.docker.distribution.manifest.list.v2+json":
1818 return parseManifestListAnnotations(manifestData)
1919 default:
2020 return map[string]string{}, fmt.Errorf("unsupported manifest media type: %s", contentType)
@@ -27,11 +27,11 @@ func parseOCIManifestAnnotations(manifestData []byte) (map[string]string, error)
2727 if err := json.Unmarshal(manifestData, &manifest); err != nil {
2828 return nil, fmt.Errorf("failed to parse OCI manifest: %w", err)
2929 }
30-
30+
3131 if manifest.Annotations == nil {
3232 return map[string]string{}, nil
3333 }
34-
34+
3535 return manifest.Annotations, nil
3636 }
3737
@@ -41,11 +41,11 @@ func parseManifestListAnnotations(manifestData []byte) (map[string]string, error
4141 if err := json.Unmarshal(manifestData, &manifestList); err != nil {
4242 return nil, fmt.Errorf("failed to parse manifest list: %w", err)
4343 }
44-
44+
4545 if manifestList.Annotations == nil {
4646 return map[string]string{}, nil
4747 }
48-
48+
4949 return manifestList.Annotations, nil
5050 }
5151
@@ -62,7 +62,6 @@ func GetDeploymentVersion(annotations map[string]string) string {
6262 if version, exists := annotations["version"]; exists && version != "" {
6363 return version
6464 }
65-
65+
6666 return ""
6767 }
68-
@@ -14,7 +14,7 @@ func ParseManifestAnnotations(manifestData []byte, contentType string) (map[stri
14 // Docker v2.2 manifests don't support annotations at manifest level14 // Docker v2.2 manifests don't support annotations at manifest level
15 return map[string]string{}, nil15 return map[string]string{}, nil
16 case "application/vnd.oci.image.index.v1+json",16 case "application/vnd.oci.image.index.v1+json",
17- "application/vnd.docker.distribution.manifest.list.v2+json":17+ "application/vnd.docker.distribution.manifest.list.v2+json":
18 return parseManifestListAnnotations(manifestData)18 return parseManifestListAnnotations(manifestData)
19 default:19 default:
20 return map[string]string{}, fmt.Errorf("unsupported manifest media type: %s", contentType)20 return map[string]string{}, fmt.Errorf("unsupported manifest media type: %s", contentType)
@@ -27,11 +27,11 @@ func parseOCIManifestAnnotations(manifestData []byte) (map[string]string, error)
27 if err := json.Unmarshal(manifestData, &manifest); err != nil {27 if err := json.Unmarshal(manifestData, &manifest); err != nil {
28 return nil, fmt.Errorf("failed to parse OCI manifest: %w", err)28 return nil, fmt.Errorf("failed to parse OCI manifest: %w", err)
29 }29 }
30- 30+
31 if manifest.Annotations == nil {31 if manifest.Annotations == nil {
32 return map[string]string{}, nil32 return map[string]string{}, nil
33 }33 }
34- 34+
35 return manifest.Annotations, nil35 return manifest.Annotations, nil
36 }36 }
37 37
@@ -41,11 +41,11 @@ func parseManifestListAnnotations(manifestData []byte) (map[string]string, error
41 if err := json.Unmarshal(manifestData, &manifestList); err != nil {41 if err := json.Unmarshal(manifestData, &manifestList); err != nil {
42 return nil, fmt.Errorf("failed to parse manifest list: %w", err)42 return nil, fmt.Errorf("failed to parse manifest list: %w", err)
43 }43 }
44- 44+
45 if manifestList.Annotations == nil {45 if manifestList.Annotations == nil {
46 return map[string]string{}, nil46 return map[string]string{}, nil
47 }47 }
48- 48+
49 return manifestList.Annotations, nil49 return manifestList.Annotations, nil
50 }50 }
51 51
@@ -62,7 +62,6 @@ func GetDeploymentVersion(annotations map[string]string) string {
62 if version, exists := annotations["version"]; exists && version != "" {62 if version, exists := annotations["version"]; exists && version != "" {
63 return version63 return version
64 }64 }
65- 65+
66 return ""66 return ""
67 }67 }
68-
M pkg/manifest/annotations_test.go +27 -27
@@ -10,12 +10,12 @@ import (
1010
1111 func TestParseManifestAnnotations(t *testing.T) {
1212 tests := []struct {
13- name string
14- manifestData []byte
15- contentType string
13+ name string
14+ manifestData []byte
15+ contentType string
1616 expectedAnnotations map[string]string
17- expectedError bool
18- errorContains string
17+ expectedError bool
18+ errorContains string
1919 }{
2020 {
2121 name: "OCI manifest with annotations",
@@ -53,7 +53,7 @@ func TestParseManifestAnnotations(t *testing.T) {
5353 },
5454 "layers": []
5555 }`),
56- contentType: "application/vnd.oci.image.manifest.v1+json",
56+ contentType: "application/vnd.oci.image.manifest.v1+json",
5757 expectedAnnotations: map[string]string{},
5858 },
5959 {
@@ -69,7 +69,7 @@ func TestParseManifestAnnotations(t *testing.T) {
6969 "layers": [],
7070 "annotations": {}
7171 }`),
72- contentType: "application/vnd.oci.image.manifest.v1+json",
72+ contentType: "application/vnd.oci.image.manifest.v1+json",
7373 expectedAnnotations: map[string]string{},
7474 },
7575 {
@@ -84,7 +84,7 @@ func TestParseManifestAnnotations(t *testing.T) {
8484 },
8585 "layers": []
8686 }`),
87- contentType: "application/vnd.docker.distribution.manifest.v2+json",
87+ contentType: "application/vnd.docker.distribution.manifest.v2+json",
8888 expectedAnnotations: map[string]string{},
8989 },
9090 {
@@ -126,7 +126,7 @@ func TestParseManifestAnnotations(t *testing.T) {
126126 "mediaType": "application/vnd.oci.image.index.v1+json",
127127 "manifests": []
128128 }`),
129- contentType: "application/vnd.oci.image.index.v1+json",
129+ contentType: "application/vnd.oci.image.index.v1+json",
130130 expectedAnnotations: map[string]string{},
131131 },
132132 {
@@ -208,11 +208,11 @@ func TestParseManifestAnnotations(t *testing.T) {
208208
209209 func TestParseOCIManifestAnnotations(t *testing.T) {
210210 tests := []struct {
211- name string
212- manifestData []byte
211+ name string
212+ manifestData []byte
213213 expectedAnnotations map[string]string
214- expectedError bool
215- errorContains string
214+ expectedError bool
215+ errorContains string
216216 }{
217217 {
218218 name: "valid OCI manifest with annotations",
@@ -259,8 +259,8 @@ func TestParseOCIManifestAnnotations(t *testing.T) {
259259 errorContains: "failed to parse OCI manifest",
260260 },
261261 {
262- name: "empty manifest data",
263- manifestData: []byte(`{}`),
262+ name: "empty manifest data",
263+ manifestData: []byte(`{}`),
264264 expectedAnnotations: map[string]string{},
265265 },
266266 }
@@ -284,11 +284,11 @@ func TestParseOCIManifestAnnotations(t *testing.T) {
284284
285285 func TestParseManifestListAnnotations(t *testing.T) {
286286 tests := []struct {
287- name string
288- manifestData []byte
287+ name string
288+ manifestData []byte
289289 expectedAnnotations map[string]string
290- expectedError bool
291- errorContains string
290+ expectedError bool
291+ errorContains string
292292 }{
293293 {
294294 name: "valid manifest list with annotations",
@@ -325,8 +325,8 @@ func TestParseManifestListAnnotations(t *testing.T) {
325325 errorContains: "failed to parse manifest list",
326326 },
327327 {
328- name: "empty manifest list",
329- manifestData: []byte(`{}`),
328+ name: "empty manifest list",
329+ manifestData: []byte(`{}`),
330330 expectedAnnotations: map[string]string{},
331331 },
332332 }
@@ -406,9 +406,9 @@ func TestIsVersionedDeployment(t *testing.T) {
406406 {
407407 name: "multiple version-like annotations",
408408 annotations: map[string]string{
409- "app-version": "1.0.0",
410- "image-version": "2.0.0",
411- "semver": "3.0.0",
409+ "app-version": "1.0.0",
410+ "image-version": "2.0.0",
411+ "semver": "3.0.0",
412412 },
413413 expected: false, // Only exact "version" key should match
414414 },
@@ -638,8 +638,8 @@ func TestAnnotations_Integration(t *testing.T) {
638638 },
639639 Layers: []OCIDescriptor{},
640640 Annotations: map[string]string{
641- "version": "1.0.0",
642- "description": "Round trip test",
641+ "version": "1.0.0",
642+ "description": "Round trip test",
643643 },
644644 }
645645
@@ -658,4 +658,4 @@ func TestAnnotations_Integration(t *testing.T) {
658658 assert.True(t, IsVersionedDeployment(annotations))
659659 assert.Equal(t, "1.0.0", GetDeploymentVersion(annotations))
660660 })
661-}⏎̸
661+}
@@ -10,12 +10,12 @@ import (
10 10
11 func TestParseManifestAnnotations(t *testing.T) {11 func TestParseManifestAnnotations(t *testing.T) {
12 tests := []struct {12 tests := []struct {
13- name string13+ name string
14- manifestData []byte14+ manifestData []byte
15- contentType string15+ contentType string
16 expectedAnnotations map[string]string16 expectedAnnotations map[string]string
17- expectedError bool17+ expectedError bool
18- errorContains string18+ errorContains string
19 }{19 }{
20 {20 {
21 name: "OCI manifest with annotations",21 name: "OCI manifest with annotations",
@@ -53,7 +53,7 @@ func TestParseManifestAnnotations(t *testing.T) {
53 },53 },
54 "layers": []54 "layers": []
55 }`),55 }`),
56- contentType: "application/vnd.oci.image.manifest.v1+json",56+ contentType: "application/vnd.oci.image.manifest.v1+json",
57 expectedAnnotations: map[string]string{},57 expectedAnnotations: map[string]string{},
58 },58 },
59 {59 {
@@ -69,7 +69,7 @@ func TestParseManifestAnnotations(t *testing.T) {
69 "layers": [],69 "layers": [],
70 "annotations": {}70 "annotations": {}
71 }`),71 }`),
72- contentType: "application/vnd.oci.image.manifest.v1+json",72+ contentType: "application/vnd.oci.image.manifest.v1+json",
73 expectedAnnotations: map[string]string{},73 expectedAnnotations: map[string]string{},
74 },74 },
75 {75 {
@@ -84,7 +84,7 @@ func TestParseManifestAnnotations(t *testing.T) {
84 },84 },
85 "layers": []85 "layers": []
86 }`),86 }`),
87- contentType: "application/vnd.docker.distribution.manifest.v2+json",87+ contentType: "application/vnd.docker.distribution.manifest.v2+json",
88 expectedAnnotations: map[string]string{},88 expectedAnnotations: map[string]string{},
89 },89 },
90 {90 {
@@ -126,7 +126,7 @@ func TestParseManifestAnnotations(t *testing.T) {
126 "mediaType": "application/vnd.oci.image.index.v1+json",126 "mediaType": "application/vnd.oci.image.index.v1+json",
127 "manifests": []127 "manifests": []
128 }`),128 }`),
129- contentType: "application/vnd.oci.image.index.v1+json",129+ contentType: "application/vnd.oci.image.index.v1+json",
130 expectedAnnotations: map[string]string{},130 expectedAnnotations: map[string]string{},
131 },131 },
132 {132 {
@@ -208,11 +208,11 @@ func TestParseManifestAnnotations(t *testing.T) {
208 208
209 func TestParseOCIManifestAnnotations(t *testing.T) {209 func TestParseOCIManifestAnnotations(t *testing.T) {
210 tests := []struct {210 tests := []struct {
211- name string211+ name string
212- manifestData []byte212+ manifestData []byte
213 expectedAnnotations map[string]string213 expectedAnnotations map[string]string
214- expectedError bool214+ expectedError bool
215- errorContains string215+ errorContains string
216 }{216 }{
217 {217 {
218 name: "valid OCI manifest with annotations",218 name: "valid OCI manifest with annotations",
@@ -259,8 +259,8 @@ func TestParseOCIManifestAnnotations(t *testing.T) {
259 errorContains: "failed to parse OCI manifest",259 errorContains: "failed to parse OCI manifest",
260 },260 },
261 {261 {
262- name: "empty manifest data",262+ name: "empty manifest data",
263- manifestData: []byte(`{}`),263+ manifestData: []byte(`{}`),
264 expectedAnnotations: map[string]string{},264 expectedAnnotations: map[string]string{},
265 },265 },
266 }266 }
@@ -284,11 +284,11 @@ func TestParseOCIManifestAnnotations(t *testing.T) {
284 284
285 func TestParseManifestListAnnotations(t *testing.T) {285 func TestParseManifestListAnnotations(t *testing.T) {
286 tests := []struct {286 tests := []struct {
287- name string287+ name string
288- manifestData []byte288+ manifestData []byte
289 expectedAnnotations map[string]string289 expectedAnnotations map[string]string
290- expectedError bool290+ expectedError bool
291- errorContains string291+ errorContains string
292 }{292 }{
293 {293 {
294 name: "valid manifest list with annotations",294 name: "valid manifest list with annotations",
@@ -325,8 +325,8 @@ func TestParseManifestListAnnotations(t *testing.T) {
325 errorContains: "failed to parse manifest list",325 errorContains: "failed to parse manifest list",
326 },326 },
327 {327 {
328- name: "empty manifest list",328+ name: "empty manifest list",
329- manifestData: []byte(`{}`),329+ manifestData: []byte(`{}`),
330 expectedAnnotations: map[string]string{},330 expectedAnnotations: map[string]string{},
331 },331 },
332 }332 }
@@ -406,9 +406,9 @@ func TestIsVersionedDeployment(t *testing.T) {
406 {406 {
407 name: "multiple version-like annotations",407 name: "multiple version-like annotations",
408 annotations: map[string]string{408 annotations: map[string]string{
409- "app-version": "1.0.0",409+ "app-version": "1.0.0",
410- "image-version": "2.0.0",410+ "image-version": "2.0.0",
411- "semver": "3.0.0",411+ "semver": "3.0.0",
412 },412 },
413 expected: false, // Only exact "version" key should match413 expected: false, // Only exact "version" key should match
414 },414 },
@@ -638,8 +638,8 @@ func TestAnnotations_Integration(t *testing.T) {
638 },638 },
639 Layers: []OCIDescriptor{},639 Layers: []OCIDescriptor{},
640 Annotations: map[string]string{640 Annotations: map[string]string{
641- "version": "1.0.0",641+ "version": "1.0.0",
642- "description": "Round trip test",642+ "description": "Round trip test",
643 },643 },
644 }644 }
645 645
@@ -658,4 +658,4 @@ func TestAnnotations_Integration(t *testing.T) {
658 assert.True(t, IsVersionedDeployment(annotations))658 assert.True(t, IsVersionedDeployment(annotations))
659 assert.Equal(t, "1.0.0", GetDeploymentVersion(annotations))659 assert.Equal(t, "1.0.0", GetDeploymentVersion(annotations))
660 })660 })
661-}⏎̸661+}
M pkg/manifest/types.go +19 -19
@@ -2,19 +2,19 @@ package manifest
22
33 // OCIManifest represents an OCI image manifest structure
44 type OCIManifest struct {
5- SchemaVersion int `json:"schemaVersion"`
6- MediaType string `json:"mediaType"`
7- Config OCIDescriptor `json:"config"`
8- Layers []OCIDescriptor `json:"layers"`
9- Annotations map[string]string `json:"annotations,omitempty"`
5+ SchemaVersion int `json:"schemaVersion"`
6+ MediaType string `json:"mediaType"`
7+ Config OCIDescriptor `json:"config"`
8+ Layers []OCIDescriptor `json:"layers"`
9+ Annotations map[string]string `json:"annotations,omitempty"`
1010 }
1111
12-// DockerManifest represents a Docker v2.2 manifest structure
12+// DockerManifest represents a Docker v2.2 manifest structure
1313 type DockerManifest struct {
14- SchemaVersion int `json:"schemaVersion"`
15- MediaType string `json:"mediaType"`
16- Config OCIDescriptor `json:"config"`
17- Layers []OCIDescriptor `json:"layers"`
14+ SchemaVersion int `json:"schemaVersion"`
15+ MediaType string `json:"mediaType"`
16+ Config OCIDescriptor `json:"config"`
17+ Layers []OCIDescriptor `json:"layers"`
1818 }
1919
2020 // OCIDescriptor represents a content descriptor
@@ -27,10 +27,10 @@ type OCIDescriptor struct {
2727
2828 // ManifestList represents a multi-platform manifest list
2929 type ManifestList struct {
30- SchemaVersion int `json:"schemaVersion"`
31- MediaType string `json:"mediaType"`
32- Manifests []ManifestDescriptor `json:"manifests"`
33- Annotations map[string]string `json:"annotations,omitempty"`
30+ SchemaVersion int `json:"schemaVersion"`
31+ MediaType string `json:"mediaType"`
32+ Manifests []ManifestDescriptor `json:"manifests"`
33+ Annotations map[string]string `json:"annotations,omitempty"`
3434 }
3535
3636 // ManifestDescriptor represents a manifest in a manifest list
@@ -44,9 +44,9 @@ type ManifestDescriptor struct {
4444
4545 // Platform represents the platform information
4646 type Platform struct {
47- Architecture string `json:"architecture"`
48- OS string `json:"os"`
49- OSVersion string `json:"os.version,omitempty"`
47+ Architecture string `json:"architecture"`
48+ OS string `json:"os"`
49+ OSVersion string `json:"os.version,omitempty"`
5050 OSFeatures []string `json:"os.features,omitempty"`
51- Variant string `json:"variant,omitempty"`
52-}⏎̸
51+ Variant string `json:"variant,omitempty"`
52+}
@@ -2,19 +2,19 @@ package manifest
2 2
3 // OCIManifest represents an OCI image manifest structure3 // OCIManifest represents an OCI image manifest structure
4 type OCIManifest struct {4 type OCIManifest struct {
5- SchemaVersion int `json:"schemaVersion"`5+ SchemaVersion int `json:"schemaVersion"`
6- MediaType string `json:"mediaType"`6+ MediaType string `json:"mediaType"`
7- Config OCIDescriptor `json:"config"`7+ Config OCIDescriptor `json:"config"`
8- Layers []OCIDescriptor `json:"layers"`8+ Layers []OCIDescriptor `json:"layers"`
9- Annotations map[string]string `json:"annotations,omitempty"`9+ Annotations map[string]string `json:"annotations,omitempty"`
10 }10 }
11 11
12-// DockerManifest represents a Docker v2.2 manifest structure 12+// DockerManifest represents a Docker v2.2 manifest structure
13 type DockerManifest struct {13 type DockerManifest struct {
14- SchemaVersion int `json:"schemaVersion"`14+ SchemaVersion int `json:"schemaVersion"`
15- MediaType string `json:"mediaType"`15+ MediaType string `json:"mediaType"`
16- Config OCIDescriptor `json:"config"`16+ Config OCIDescriptor `json:"config"`
17- Layers []OCIDescriptor `json:"layers"`17+ Layers []OCIDescriptor `json:"layers"`
18 }18 }
19 19
20 // OCIDescriptor represents a content descriptor20 // OCIDescriptor represents a content descriptor
@@ -27,10 +27,10 @@ type OCIDescriptor struct {
27 27
28 // ManifestList represents a multi-platform manifest list28 // ManifestList represents a multi-platform manifest list
29 type ManifestList struct {29 type ManifestList struct {
30- SchemaVersion int `json:"schemaVersion"`30+ SchemaVersion int `json:"schemaVersion"`
31- MediaType string `json:"mediaType"`31+ MediaType string `json:"mediaType"`
32- Manifests []ManifestDescriptor `json:"manifests"`32+ Manifests []ManifestDescriptor `json:"manifests"`
33- Annotations map[string]string `json:"annotations,omitempty"`33+ Annotations map[string]string `json:"annotations,omitempty"`
34 }34 }
35 35
36 // ManifestDescriptor represents a manifest in a manifest list36 // ManifestDescriptor represents a manifest in a manifest list
@@ -44,9 +44,9 @@ type ManifestDescriptor struct {
44 44
45 // Platform represents the platform information45 // Platform represents the platform information
46 type Platform struct {46 type Platform struct {
47- Architecture string `json:"architecture"`47+ Architecture string `json:"architecture"`
48- OS string `json:"os"`48+ OS string `json:"os"`
49- OSVersion string `json:"os.version,omitempty"`49+ OSVersion string `json:"os.version,omitempty"`
50 OSFeatures []string `json:"os.features,omitempty"`50 OSFeatures []string `json:"os.features,omitempty"`
51- Variant string `json:"variant,omitempty"`51+ Variant string `json:"variant,omitempty"`
52-}⏎̸52+}
M pkg/manifest/types_test.go +8 -8
@@ -458,8 +458,8 @@ func TestManifestDescriptor_JSON(t *testing.T) {
458458 Variant: "power9",
459459 },
460460 Annotations: map[string]string{
461- "build.date": "2023-01-01T00:00:00Z",
462- "maintainer": "gordon-team",
461+ "build.date": "2023-01-01T00:00:00Z",
462+ "maintainer": "gordon-team",
463463 "io.buildah.version": "1.23.0",
464464 },
465465 },
@@ -493,13 +493,13 @@ func TestManifestTypes_EdgeCases(t *testing.T) {
493493 Digest: "sha256:config",
494494 Size: 100,
495495 },
496- Layers: []OCIDescriptor{},
496+ Layers: []OCIDescriptor{},
497497 Annotations: map[string]string{}, // Empty map should be omitted
498498 }
499499
500500 jsonData, err := json.Marshal(manifest)
501501 require.NoError(t, err)
502-
502+
503503 // Should not contain "annotations" field
504504 assert.NotContains(t, string(jsonData), "annotations")
505505 })
@@ -519,7 +519,7 @@ func TestManifestTypes_EdgeCases(t *testing.T) {
519519
520520 jsonData, err := json.Marshal(manifest)
521521 require.NoError(t, err)
522-
522+
523523 // Should not contain "annotations" field
524524 assert.NotContains(t, string(jsonData), "annotations")
525525 })
@@ -534,7 +534,7 @@ func TestManifestTypes_EdgeCases(t *testing.T) {
534534
535535 jsonData, err := json.Marshal(descriptor)
536536 require.NoError(t, err)
537-
537+
538538 // Should not contain "platform" field
539539 assert.NotContains(t, string(jsonData), "platform")
540540 })
@@ -549,9 +549,9 @@ func TestManifestTypes_EdgeCases(t *testing.T) {
549549
550550 jsonData, err := json.Marshal(platform)
551551 require.NoError(t, err)
552-
552+
553553 // Empty strings should be preserved
554554 assert.Contains(t, string(jsonData), `"architecture":""`)
555555 assert.Contains(t, string(jsonData), `"os":""`)
556556 })
557-}⏎̸
557+}
@@ -458,8 +458,8 @@ func TestManifestDescriptor_JSON(t *testing.T) {
458 Variant: "power9",458 Variant: "power9",
459 },459 },
460 Annotations: map[string]string{460 Annotations: map[string]string{
461- "build.date": "2023-01-01T00:00:00Z",461+ "build.date": "2023-01-01T00:00:00Z",
462- "maintainer": "gordon-team",462+ "maintainer": "gordon-team",
463 "io.buildah.version": "1.23.0",463 "io.buildah.version": "1.23.0",
464 },464 },
465 },465 },
@@ -493,13 +493,13 @@ func TestManifestTypes_EdgeCases(t *testing.T) {
493 Digest: "sha256:config",493 Digest: "sha256:config",
494 Size: 100,494 Size: 100,
495 },495 },
496- Layers: []OCIDescriptor{},496+ Layers: []OCIDescriptor{},
497 Annotations: map[string]string{}, // Empty map should be omitted497 Annotations: map[string]string{}, // Empty map should be omitted
498 }498 }
499 499
500 jsonData, err := json.Marshal(manifest)500 jsonData, err := json.Marshal(manifest)
501 require.NoError(t, err)501 require.NoError(t, err)
502- 502+
503 // Should not contain "annotations" field503 // Should not contain "annotations" field
504 assert.NotContains(t, string(jsonData), "annotations")504 assert.NotContains(t, string(jsonData), "annotations")
505 })505 })
@@ -519,7 +519,7 @@ func TestManifestTypes_EdgeCases(t *testing.T) {
519 519
520 jsonData, err := json.Marshal(manifest)520 jsonData, err := json.Marshal(manifest)
521 require.NoError(t, err)521 require.NoError(t, err)
522- 522+
523 // Should not contain "annotations" field523 // Should not contain "annotations" field
524 assert.NotContains(t, string(jsonData), "annotations")524 assert.NotContains(t, string(jsonData), "annotations")
525 })525 })
@@ -534,7 +534,7 @@ func TestManifestTypes_EdgeCases(t *testing.T) {
534 534
535 jsonData, err := json.Marshal(descriptor)535 jsonData, err := json.Marshal(descriptor)
536 require.NoError(t, err)536 require.NoError(t, err)
537- 537+
538 // Should not contain "platform" field538 // Should not contain "platform" field
539 assert.NotContains(t, string(jsonData), "platform")539 assert.NotContains(t, string(jsonData), "platform")
540 })540 })
@@ -549,9 +549,9 @@ func TestManifestTypes_EdgeCases(t *testing.T) {
549 549
550 jsonData, err := json.Marshal(platform)550 jsonData, err := json.Marshal(platform)
551 require.NoError(t, err)551 require.NoError(t, err)
552- 552+
553 // Empty strings should be preserved553 // Empty strings should be preserved
554 assert.Contains(t, string(jsonData), `"architecture":""`)554 assert.Contains(t, string(jsonData), `"architecture":""`)
555 assert.Contains(t, string(jsonData), `"os":""`)555 assert.Contains(t, string(jsonData), `"os":""`)
556 })556 })
557-}⏎̸557+}
M pkg/runtime/interface.go +20 -20
@@ -7,21 +7,21 @@ import (
77
88 // Container represents a running container
99 type Container struct {
10- ID string
11- Image string
12- Name string
13- Status string
14- Ports []int
15- Labels map[string]string
10+ ID string
11+ Image string
12+ Name string
13+ Status string
14+ Ports []int
15+ Labels map[string]string
1616 }
1717
1818 // NetworkInfo represents a network
1919 type NetworkInfo struct {
20- ID string
21- Name string
22- Driver string
23- Containers []string
24- Labels map[string]string
20+ ID string
21+ Name string
22+ Driver string
23+ Containers []string
24+ Labels map[string]string
2525 }
2626
2727 // ContainerConfig holds configuration for creating a container
@@ -48,40 +48,40 @@ type Runtime interface {
4848 StopContainer(ctx context.Context, containerID string) error
4949 RestartContainer(ctx context.Context, containerID string) error
5050 RemoveContainer(ctx context.Context, containerID string, force bool) error
51-
51+
5252 // Container inspection
5353 ListContainers(ctx context.Context, all bool) ([]*Container, error)
5454 InspectContainer(ctx context.Context, containerID string) (*Container, error)
5555 GetContainerLogs(ctx context.Context, containerID string, follow bool) (io.ReadCloser, error)
56-
56+
5757 // Image operations
5858 PullImage(ctx context.Context, image string) error
5959 PullImageWithAuth(ctx context.Context, image, username, password string) error
6060 RemoveImage(ctx context.Context, image string, force bool) error
6161 ListImages(ctx context.Context) ([]string, error)
62-
62+
6363 // Runtime information
6464 Ping(ctx context.Context) error
6565 Version(ctx context.Context) (string, error)
66-
66+
6767 // Health and status
6868 IsContainerRunning(ctx context.Context, containerID string) (bool, error)
6969 GetContainerPort(ctx context.Context, containerID string, internalPort int) (int, error)
70-
70+
7171 // Image and port inspection
7272 GetImageExposedPorts(ctx context.Context, imageRef string) ([]int, error)
7373 GetContainerExposedPorts(ctx context.Context, containerID string) ([]int, error)
7474 GetContainerNetworkInfo(ctx context.Context, containerID string) (string, int, error)
75-
75+
7676 // Volume management
7777 InspectImageVolumes(ctx context.Context, imageRef string) ([]string, error)
7878 VolumeExists(ctx context.Context, volumeName string) (bool, error)
7979 CreateVolume(ctx context.Context, volumeName string) error
8080 RemoveVolume(ctx context.Context, volumeName string, force bool) error
81-
81+
8282 // Environment inspection
8383 InspectImageEnv(ctx context.Context, imageRef string) ([]string, error)
84-
84+
8585 // Network management
8686 CreateNetwork(ctx context.Context, name string, options map[string]string) error
8787 RemoveNetwork(ctx context.Context, name string) error
@@ -89,4 +89,4 @@ type Runtime interface {
8989 NetworkExists(ctx context.Context, name string) (bool, error)
9090 ConnectContainerToNetwork(ctx context.Context, containerName, networkName string) error
9191 DisconnectContainerFromNetwork(ctx context.Context, containerName, networkName string) error
92-}⏎̸
92+}
@@ -7,21 +7,21 @@ import (
7 7
8 // Container represents a running container8 // Container represents a running container
9 type Container struct {9 type Container struct {
10- ID string10+ ID string
11- Image string11+ Image string
12- Name string12+ Name string
13- Status string13+ Status string
14- Ports []int14+ Ports []int
15- Labels map[string]string15+ Labels map[string]string
16 }16 }
17 17
18 // NetworkInfo represents a network18 // NetworkInfo represents a network
19 type NetworkInfo struct {19 type NetworkInfo struct {
20- ID string20+ ID string
21- Name string21+ Name string
22- Driver string22+ Driver string
23- Containers []string23+ Containers []string
24- Labels map[string]string24+ Labels map[string]string
25 }25 }
26 26
27 // ContainerConfig holds configuration for creating a container27 // ContainerConfig holds configuration for creating a container
@@ -48,40 +48,40 @@ type Runtime interface {
48 StopContainer(ctx context.Context, containerID string) error48 StopContainer(ctx context.Context, containerID string) error
49 RestartContainer(ctx context.Context, containerID string) error49 RestartContainer(ctx context.Context, containerID string) error
50 RemoveContainer(ctx context.Context, containerID string, force bool) error50 RemoveContainer(ctx context.Context, containerID string, force bool) error
51- 51+
52 // Container inspection52 // Container inspection
53 ListContainers(ctx context.Context, all bool) ([]*Container, error)53 ListContainers(ctx context.Context, all bool) ([]*Container, error)
54 InspectContainer(ctx context.Context, containerID string) (*Container, error)54 InspectContainer(ctx context.Context, containerID string) (*Container, error)
55 GetContainerLogs(ctx context.Context, containerID string, follow bool) (io.ReadCloser, error)55 GetContainerLogs(ctx context.Context, containerID string, follow bool) (io.ReadCloser, error)
56- 56+
57 // Image operations57 // Image operations
58 PullImage(ctx context.Context, image string) error58 PullImage(ctx context.Context, image string) error
59 PullImageWithAuth(ctx context.Context, image, username, password string) error59 PullImageWithAuth(ctx context.Context, image, username, password string) error
60 RemoveImage(ctx context.Context, image string, force bool) error60 RemoveImage(ctx context.Context, image string, force bool) error
61 ListImages(ctx context.Context) ([]string, error)61 ListImages(ctx context.Context) ([]string, error)
62- 62+
63 // Runtime information63 // Runtime information
64 Ping(ctx context.Context) error64 Ping(ctx context.Context) error
65 Version(ctx context.Context) (string, error)65 Version(ctx context.Context) (string, error)
66- 66+
67 // Health and status67 // Health and status
68 IsContainerRunning(ctx context.Context, containerID string) (bool, error)68 IsContainerRunning(ctx context.Context, containerID string) (bool, error)
69 GetContainerPort(ctx context.Context, containerID string, internalPort int) (int, error)69 GetContainerPort(ctx context.Context, containerID string, internalPort int) (int, error)
70- 70+
71 // Image and port inspection71 // Image and port inspection
72 GetImageExposedPorts(ctx context.Context, imageRef string) ([]int, error)72 GetImageExposedPorts(ctx context.Context, imageRef string) ([]int, error)
73 GetContainerExposedPorts(ctx context.Context, containerID string) ([]int, error)73 GetContainerExposedPorts(ctx context.Context, containerID string) ([]int, error)
74 GetContainerNetworkInfo(ctx context.Context, containerID string) (string, int, error)74 GetContainerNetworkInfo(ctx context.Context, containerID string) (string, int, error)
75- 75+
76 // Volume management76 // Volume management
77 InspectImageVolumes(ctx context.Context, imageRef string) ([]string, error)77 InspectImageVolumes(ctx context.Context, imageRef string) ([]string, error)
78 VolumeExists(ctx context.Context, volumeName string) (bool, error)78 VolumeExists(ctx context.Context, volumeName string) (bool, error)
79 CreateVolume(ctx context.Context, volumeName string) error79 CreateVolume(ctx context.Context, volumeName string) error
80 RemoveVolume(ctx context.Context, volumeName string, force bool) error80 RemoveVolume(ctx context.Context, volumeName string, force bool) error
81- 81+
82 // Environment inspection82 // Environment inspection
83 InspectImageEnv(ctx context.Context, imageRef string) ([]string, error)83 InspectImageEnv(ctx context.Context, imageRef string) ([]string, error)
84- 84+
85 // Network management85 // Network management
86 CreateNetwork(ctx context.Context, name string, options map[string]string) error86 CreateNetwork(ctx context.Context, name string, options map[string]string) error
87 RemoveNetwork(ctx context.Context, name string) error87 RemoveNetwork(ctx context.Context, name string) error
@@ -89,4 +89,4 @@ type Runtime interface {
89 NetworkExists(ctx context.Context, name string) (bool, error)89 NetworkExists(ctx context.Context, name string) (bool, error)
90 ConnectContainerToNetwork(ctx context.Context, containerName, networkName string) error90 ConnectContainerToNetwork(ctx context.Context, containerName, networkName string) error
91 DisconnectContainerFromNetwork(ctx context.Context, containerName, networkName string) error91 DisconnectContainerFromNetwork(ctx context.Context, containerName, networkName string) error
92-}⏎̸92+}

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