diff --git a/CHANGELOG.md b/CHANGELOG.md index 31dccc64..47dc7eb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # EDGEGRID GOLANG RELEASE NOTES +## 8.1.0 (April 11, 2024) + +#### FEATURES/ENHANCEMENTS: + +* DNS + * Modified `ParseRData` method to remove priority, weight and port from targets **only** when those values are same for all `SRV` targets. + Otherwise, targets are returned untouched and `priority`, `weight` and `port` in the map are not populated. + +* Image and Video Manager + * Added `SmartCrop` transformation + ## 8.0.0 (March 19, 2024) #### BREAKING CHANGES: diff --git a/Makefile b/Makefile index b10f6d5e..9911609a 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ VERSION ?= $(shell git describe --tags --always | grep '^v\d' || \ BIN = $(CURDIR)/bin GOLANGCI_LINT_VERSION = v1.55.2 GO = go +GOMODTIDY = $(GO) mod tidy TIMEOUT = 15 V = 0 Q = $(if $(filter 1,$V),,@) @@ -42,7 +43,7 @@ $(BIN)/golangci-lint: ; $(info $(M) Installing golangci-lint...) @ .PHONY: all -all: clean fmt-check lint test-verbose create-junit-report create-coverage-files clean-tools +all: clean tidy fmt-check lint test-verbose create-junit-report create-coverage-files clean-tools # Tests @@ -83,6 +84,10 @@ create-coverage-files: | $(GOCOV) $(GOCOVXML); $(info $(M) Creating coverage fil lint: | $(GOLANGCILINT) ; $(info $(M) Running golangci-lint...) @ $Q $(BIN)/golangci-lint run +.PHONY: tidy +tidy: ; $(info $(M) Running go mod tidy...) @ + @$(GOMODTIDY) + .PHONY: fmt fmt: | $(GOIMPORTS); $(info $(M) Running goimports...) @ ## Run goimports on all source files $Q $(GOIMPORTS) -w . diff --git a/pkg/dns/record_lookup.go b/pkg/dns/record_lookup.go index fdc15cee..2d52288a 100644 --- a/pkg/dns/record_lookup.go +++ b/pkg/dns/record_lookup.go @@ -387,15 +387,39 @@ func resolveRRSIGType(rData []string, fieldMap map[string]interface{}) { } func resolveSRVType(rData, newRData []string, fieldMap map[string]interface{}) { - // pull out some fields - parts := strings.Split(rData[0], " ") - fieldMap["priority"], _ = strconv.Atoi(parts[0]) - fieldMap["weight"], _ = strconv.Atoi(parts[1]) - fieldMap["port"], _ = strconv.Atoi(parts[2]) - // populate target + // if all targets have the same priority, weight and port, process it in the old way + priorityMap := make(map[int]struct{}) + weightMap := make(map[int]struct{}) + portMap := make(map[int]struct{}) for _, rContent := range rData { - parts = strings.Split(rContent, " ") - newRData = append(newRData, parts[3]) + parts := strings.Split(rContent, " ") + priority, _ := strconv.Atoi(parts[0]) + weight, _ := strconv.Atoi(parts[1]) + port, _ := strconv.Atoi(parts[2]) + priorityMap[priority] = struct{}{} + weightMap[weight] = struct{}{} + portMap[port] = struct{}{} + } + // all values are the same, so process in the old way + if len(priorityMap) == 1 && len(weightMap) == 1 && len(portMap) == 1 { + // pull out some fields + parts := strings.Split(rData[0], " ") + fieldMap["priority"], _ = strconv.Atoi(parts[0]) + fieldMap["weight"], _ = strconv.Atoi(parts[1]) + fieldMap["port"], _ = strconv.Atoi(parts[2]) + // populate target + for _, rContent := range rData { + parts = strings.Split(rContent, " ") + newRData = append(newRData, parts[3]) + } + } else { + delete(fieldMap, "priority") + delete(fieldMap, "weight") + delete(fieldMap, "port") + // populate target + for _, rContent := range rData { + newRData = append(newRData, rContent) + } } fieldMap["target"] = newRData } diff --git a/pkg/dns/record_lookup_test.go b/pkg/dns/record_lookup_test.go index 8d939b58..ac81c8a3 100644 --- a/pkg/dns/record_lookup_test.go +++ b/pkg/dns/record_lookup_test.go @@ -318,10 +318,12 @@ func TestDNS_ParseRData(t *testing.T) { client := Client(session.Must(session.New())) tests := map[string]struct { + rType string rdata []string expect map[string]interface{} }{ "AFSDB": { + rType: "AFSDB", rdata: []string{"1 bar.com"}, expect: map[string]interface{}{ "subtype": 1, @@ -329,6 +331,7 @@ func TestDNS_ParseRData(t *testing.T) { }, }, "SVCB": { + rType: "SVCB", rdata: []string{"0 svc4.example.com."}, expect: map[string]interface{}{ "target": []string{}, @@ -337,6 +340,7 @@ func TestDNS_ParseRData(t *testing.T) { }, }, "HTTPS": { + rType: "HTTPS", rdata: []string{"3 https.example.com. alpn=bar port=8080"}, expect: map[string]interface{}{ "target": []string{}, @@ -345,11 +349,28 @@ func TestDNS_ParseRData(t *testing.T) { "svc_params": "alpn=bar port=8080", }, }, + "SRV with default values": { + rType: "SRV", + rdata: []string{"10 60 5060 big.example.com.", "10 60 5060 small.example.com."}, + expect: map[string]interface{}{ + "port": 5060, + "priority": 10, + "weight": 60, + "target": []string{"big.example.com.", "small.example.com."}, + }, + }, + "SRV without default values": { + rType: "SRV", + rdata: []string{"10 60 5060 big.example.com.", "20 50 5060 small.example.com."}, + expect: map[string]interface{}{ + "target": []string{"10 60 5060 big.example.com.", "20 50 5060 small.example.com."}, + }, + }, } for name, test := range tests { t.Run(name, func(t *testing.T) { - out := client.ParseRData(context.Background(), name, test.rdata) + out := client.ParseRData(context.Background(), test.rType, test.rdata) assert.Equal(t, test.expect, out) }) diff --git a/pkg/imaging/policy.gen.go b/pkg/imaging/policy.gen.go index 4675e52b..66b8831a 100644 --- a/pkg/imaging/policy.gen.go +++ b/pkg/imaging/policy.gen.go @@ -943,6 +943,34 @@ type ( // ShearTransformation ... ShearTransformation string + // SmartCrop Crops around whatever is most important in the image, to a region around a specified area of interest relative to the specified `width` and `height` values. The crop detects any faces present, otherwise features. + SmartCrop struct { + // Debug When enabled, the SmartCrop transformation doesn't actually execute. Instead, it outlines found faces or features, the region of interest, and the crop area. + Debug *BooleanVariableInline `json:"debug,omitempty"` + // Height The height in pixels of the output image relative to the specified `style` value. + Height *IntegerVariableInline `json:"height,omitempty"` + // Sloppy Whether to sacrifice any image fidelity for transformation performance. + Sloppy *BooleanVariableInline `json:"sloppy,omitempty"` + // Style Specifies how to crop or scale a crop area for the specified area of interest in the source image, `fill` by default. The output image resizes to the specified `width` and `height` values. A value of `crop` places raw crop around the point of interest. A value of `fill` scales the crop area to include as much of the image and point of interest as possible, relative to the specified `width` and `height` values. A value of `zoom` scales the crop area as small as possible to fit the point of interest, relative to the specified `width` and `height` values. + Style *SmartCropStyleVariableInline `json:"style,omitempty"` + // Transformation Identifies this type of transformation, `SmartCrop` in this case. + Transformation SmartCropTransformation `json:"transformation"` + // Width The width in pixels of the output image relative to the specified `style` value. + Width *IntegerVariableInline `json:"width,omitempty"` + } + + // SmartCropStyle ... + SmartCropStyle string + + // SmartCropStyleVariableInline represents a type which stores either a value or a variable name + SmartCropStyleVariableInline struct { + Name *string + Value *SmartCropStyle + } + + // SmartCropTransformation ... + SmartCropTransformation string + // StringVariableInline represents a type which stores either a value or a variable name StringVariableInline struct { Name *string @@ -1495,6 +1523,16 @@ const ( // ShearTransformationShear const ShearTransformationShear ShearTransformation = "Shear" + // SmartCropStyleCrop const + SmartCropStyleCrop SmartCropStyle = "crop" + // SmartCropStyleFill const + SmartCropStyleFill SmartCropStyle = "fill" + // SmartCropStyleZoom const + SmartCropStyleZoom SmartCropStyle = "zoom" + + // SmartCropTransformationSmartCrop const + SmartCropTransformationSmartCrop SmartCropTransformation = "SmartCrop" + // TextImageTypePostTypeText const TextImageTypePostTypeText TextImageTypePostType = "Text" @@ -1724,6 +1762,10 @@ func (Shear) transformationType() string { return "Shear" } +func (SmartCrop) transformationType() string { + return "SmartCrop" +} + func (TextImageType) imageType() string { return "TextImageType" } @@ -2123,6 +2165,16 @@ func ShearTransformationPtr(v ShearTransformation) *ShearTransformation { return &v } +// SmartCropStylePtr returns pointer of SmartCropStyle +func SmartCropStylePtr(v SmartCropStyle) *SmartCropStyle { + return &v +} + +// SmartCropTransformationPtr returns pointer of SmartCropTransformation +func SmartCropTransformationPtr(v SmartCropTransformation) *SmartCropTransformation { + return &v +} + // TextImageTypePostTypePtr returns pointer of TextImageTypePostType func TextImageTypePostTypePtr(v TextImageTypePostType) *TextImageTypePostType { return &v @@ -3166,6 +3218,31 @@ func (s Shear) Validate() error { }.Filter() } +// Validate validates SmartCrop +func (s SmartCrop) Validate() error { + return validation.Errors{ + "Debug": validation.Validate(s.Debug), + "Height": validation.Validate(s.Height), + "Sloppy": validation.Validate(s.Sloppy), + "Style": validation.Validate(s.Style), + "Transformation": validation.Validate(s.Transformation, + validation.Required, + validation.In(SmartCropTransformationSmartCrop), + ), + "Width": validation.Validate(s.Width), + }.Filter() +} + +// Validate validates SmartCropStyleVariableInline +func (s SmartCropStyleVariableInline) Validate() error { + return validation.Errors{ + "Name": validation.Validate(s.Name), + "Value": validation.Validate(s.Value, + validation.In(SmartCropStyleCrop, SmartCropStyleFill, SmartCropStyleZoom), + ), + }.Filter() +} + // Validate validates StringVariableInline func (s StringVariableInline) Validate() error { return validation.Errors{ @@ -3432,6 +3509,8 @@ var ( ErrUnmarshalVariableResizeAspectVariableInline = errors.New("unmarshalling ResizeAspectVariableInline") // ErrUnmarshalVariableResizeTypeVariableInline represents an error while unmarshalling ResizeTypeVariableInline ErrUnmarshalVariableResizeTypeVariableInline = errors.New("unmarshalling ResizeTypeVariableInline") + // ErrUnmarshalVariableSmartCropStyleVariableInline represents an error while unmarshalling SmartCropStyleVariableInline + ErrUnmarshalVariableSmartCropStyleVariableInline = errors.New("unmarshalling SmartCropStyleVariableInline") // ErrUnmarshalVariableStringVariableInline represents an error while unmarshalling StringVariableInline ErrUnmarshalVariableStringVariableInline = errors.New("unmarshalling StringVariableInline") // ErrUnmarshalVariableOutputVideoPerceptualQualityVariableInline represents an error while unmarshalling OutputVideoPerceptualQualityVariableInline @@ -4068,6 +4147,35 @@ func (r *ResizeTypeVariableInline) MarshalJSON() ([]byte, error) { return nil, nil } +// UnmarshalJSON is a custom unmarshaler used to decode a variable which can be either a value or a variable object +func (s *SmartCropStyleVariableInline) UnmarshalJSON(in []byte) error { + var err error + var variable InlineVariable + if err = json.Unmarshal(in, &variable); err == nil { + s.Name = &variable.Var + s.Value = nil + return nil + } + var value SmartCropStyle + if err = json.Unmarshal(in, &value); err == nil { + s.Name = nil + s.Value = &value + return nil + } + return fmt.Errorf("%w: %s", ErrUnmarshalVariableSmartCropStyleVariableInline, err) +} + +// MarshalJSON is a custom marshaler used to encode a variable which can be either a value or a variable object +func (s *SmartCropStyleVariableInline) MarshalJSON() ([]byte, error) { + if s.Value != nil { + return json.Marshal(*s.Value) + } + if s.Name != nil { + return json.Marshal(VariableInline{Var: *s.Name}) + } + return nil, nil +} + // UnmarshalJSON is a custom unmarshaler used to decode a variable which can be either a value or a variable object func (s *StringVariableInline) UnmarshalJSON(in []byte) error { var err error @@ -4466,6 +4574,7 @@ var TransformationHandlers = map[string]func() TransformationType{ "Rotate": func() TransformationType { return &Rotate{} }, "Scale": func() TransformationType { return &Scale{} }, "Shear": func() TransformationType { return &Shear{} }, + "SmartCrop": func() TransformationType { return &SmartCrop{} }, "Trim": func() TransformationType { return &Trim{} }, "UnsharpMask": func() TransformationType { return &UnsharpMask{} }, }