Skip to content
This repository has been archived by the owner on Oct 17, 2024. It is now read-only.

feat: switch go-yaml implementation to most recent version #535

Merged
merged 1 commit into from
Jan 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions cloudformation/policies_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cloudformation_test

import (
"github.com/sanathkr/yaml"
"gopkg.in/yaml.v3"

"github.com/awslabs/goformation/v7/cloudformation"
"github.com/awslabs/goformation/v7/cloudformation/autoscaling"
Expand Down Expand Up @@ -47,9 +47,9 @@ var _ = Describe("Goformation", func() {
},
Expected: map[string]interface{}{
"AutoScalingRollingUpdate": map[string]interface{}{
"MaxBatchSize": float64(10),
"MinInstancesInService": float64(11),
"MinSuccessfulInstancesPercent": float64(12),
"MaxBatchSize": 10,
"MinInstancesInService": 11,
"MinSuccessfulInstancesPercent": 12,
"PauseTime": "test-pause-time",
"SuspendProcesses": []interface{}{"test-suspend1", "test-suspend2"},
"WaitOnResourceSignals": true,
Expand Down Expand Up @@ -146,10 +146,10 @@ var _ = Describe("Goformation", func() {
},
Expected: map[string]interface{}{
"AutoScalingCreationPolicy": map[string]interface{}{
"MinSuccessfulInstancesPercent": float64(10),
"MinSuccessfulInstancesPercent": 10,
},
"ResourceSignal": map[string]interface{}{
"Count": float64(11),
"Count": 11,
"Timeout": "test-timeout",
},
},
Expand Down
16 changes: 13 additions & 3 deletions cloudformation/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"strings"

"github.com/awslabs/goformation/v7/intrinsics"
"github.com/sanathkr/yaml"
"gopkg.in/yaml.v3"
)

// Template represents an AWS CloudFormation template
Expand Down Expand Up @@ -231,12 +231,22 @@ func (t *Template) JSON() ([]byte, error) {

// YAML converts an AWS CloudFormation template object to YAML
func (t *Template) YAML() ([]byte, error) {

j, err := t.JSON()
if err != nil {
return nil, err
}

return yaml.JSONToYAML(j)
var jsonObj interface{}
// We are using yaml.Unmarshal here (instead of json.Unmarshal) because the
// Go JSON library doesn't try to pick the right number type (int, float,
// etc.) when unmarshalling to interface{}, it just picks float64
// universally. go-yaml does go through the effort of picking the right
// number type, so we can preserve number type throughout this process.
err = yaml.Unmarshal(j, &jsonObj)
if err != nil {
return nil, err
}

// Marshal this object into YAML
return yaml.Marshal(jsonObj)
}
4 changes: 1 addition & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ module github.com/awslabs/goformation/v7
require (
github.com/onsi/ginkgo/v2 v2.3.1
github.com/onsi/gomega v1.22.1
github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b
github.com/sanathkr/yaml v0.0.0-20170819201035-0056894fa522
github.com/xeipuuv/gojsonschema v0.0.0-20181112162635-ac52e6811b56
gopkg.in/yaml.v3 v3.0.1
)

require (
Expand All @@ -16,7 +15,6 @@ require (
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

go 1.17
26 changes: 13 additions & 13 deletions goformation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"

"github.com/sanathkr/yaml"
"gopkg.in/yaml.v3"

"github.com/awslabs/goformation/v7"
"github.com/awslabs/goformation/v7/cloudformation"
Expand Down Expand Up @@ -98,19 +98,19 @@ func Example_to_yaml() {
}

// Output:
// AWSTemplateFormatVersion: 2010-09-09
// AWSTemplateFormatVersion: "2010-09-09"
// Resources:
// MyTopic:
// Properties:
// TopicName: my-topic-1575143970
// Type: AWS::SNS::Topic
// MyTopicSubscription:
// Properties:
// Endpoint: [email protected]
// Protocol: email
// TopicArn:
// Ref: MyTopic
// Type: AWS::SNS::Subscription
// MyTopic:
// Properties:
// TopicName: my-topic-1575143970
// Type: AWS::SNS::Topic
// MyTopicSubscription:
// Properties:
// Endpoint: [email protected]
// Protocol: email
// TopicArn:
// Ref: MyTopic
// Type: AWS::SNS::Subscription

}

Expand Down
14 changes: 11 additions & 3 deletions intrinsics/intrinsics.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"encoding/json"
"fmt"

yamlwrapper "github.com/sanathkr/yaml"
"gopkg.in/yaml.v3"
)

// IntrinsicHandler is a function that applies an intrinsic function and returns
Expand Down Expand Up @@ -61,13 +61,21 @@ func ProcessYAML(input []byte, options *ProcessorOptions) ([]byte, error) {
// Convert short form intrinsic functions (e.g. !Sub) to long form
registerTagMarshallers()

data, err := yamlwrapper.YAMLToJSON(input)
// Convert YAML to an object
var yamlObj interface{}
err := yaml.Unmarshal(input, &customTagProcessor{
target: &yamlObj,
})
if err != nil {
return nil, fmt.Errorf("invalid YAML template: %s", err)
}

return ProcessJSON(data, options)
data, err := json.Marshal(yamlObj)
if err != nil {
return nil, err
}

return ProcessJSON(data, options)
}

// ProcessJSON recursively searches through a byte array of JSON data for all
Expand Down
96 changes: 75 additions & 21 deletions intrinsics/tags.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package intrinsics

import (
"reflect"

yaml "github.com/sanathkr/go-yaml"
yaml "gopkg.in/yaml.v3"
"strings"
)

var allTags = []string{
Expand All @@ -12,36 +11,91 @@ var allTags = []string{
"Equals", "Cidr", "And", "If", "Not", "Or",
}

type tagUnmarshalerType struct {
}
var tagResolvers = make(map[string]func(*yaml.Node) (*yaml.Node, error))

func (t *tagUnmarshalerType) UnmarshalYAMLTag(tag string, fieldValue reflect.Value) reflect.Value {
type fragment struct {
content *yaml.Node
}

prefix := "Fn::"
if tag == "Ref" || tag == "Condition" {
prefix = ""
}
func (f *fragment) UnmarshalYAML(value *yaml.Node) error {
var err error
f.content, err = resolveTags(value)
return err
}

tag = prefix + tag
type customTagProcessor struct {
target interface{}
}

output := reflect.ValueOf(make(map[interface{}]interface{}))
key := reflect.ValueOf(tag)
func (i *customTagProcessor) UnmarshalYAML(value *yaml.Node) error {
resolved, err := resolveTags(value)
if err != nil {
return err
}

output.SetMapIndex(key, fieldValue)
return resolved.Decode(i.target)
}

return output
func addTagResolver(tag string, resolver func(*yaml.Node) (*yaml.Node, error)) {
tagResolvers[tag] = resolver
}

var tagUnmarshaller = &tagUnmarshalerType{}
func resolveTags(node *yaml.Node) (*yaml.Node, error) {
for tag, fn := range tagResolvers {
if node.Tag == tag {
return fn(node)
}
}

func registerTagMarshallers() {
for _, tag := range allTags {
yaml.RegisterTagUnmarshaler("!"+tag, tagUnmarshaller)
if node.Kind == yaml.SequenceNode || node.Kind == yaml.MappingNode {
var err error
for i := range node.Content {
node.Content[i], err = resolveTags(node.Content[i])
if err != nil {
return nil, err
}
}
}

return node, nil
}

func unregisterTagMarshallers() {
func registerTagMarshallers() {
for _, tag := range allTags {
yaml.UnRegisterTagUnmarshaler("!" + tag)
addTagResolver("!"+tag, func(tag string) func(node *yaml.Node) (*yaml.Node, error) {
return func(node *yaml.Node) (*yaml.Node, error) {
prefix := "Fn::"
if tag == "Ref" || tag == "Condition" || strings.HasPrefix(tag, prefix) {
prefix = ""
}

tag = prefix + tag

output := &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
Value: "",
Content: []*yaml.Node{
{Kind: yaml.ScalarNode, Tag: "!!str", Value: tag},
},
}

if len(node.Content) == 0 {
output.Content = append(output.Content, &yaml.Node{
Kind: yaml.ScalarNode,
Tag: "!!str",
Value: node.Value,
})
} else {
output.Content = append(output.Content, &yaml.Node{
Kind: yaml.SequenceNode,
Tag: "!!seq",
Content: node.Content,
})
}

return output, nil
}
}(tag))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ Resources:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyLambdaFunction.Arn}/invocations
responses: {}
swagger: '2.0'



Expand Down