Skip to content

Commit

Permalink
Introduce multi-document support for YAMLs (#5)
Browse files Browse the repository at this point in the history
Added multi-document support and test cases.

Updated vendor directory.

Added support for root level simple lists.

Cleaned up the test cases to have a nice list helper function.

In the output, the document index should only be visible if there are
multiple documents loaded.
  • Loading branch information
HeavyWombat authored Apr 20, 2018
1 parent d4d09da commit e0109f6
Show file tree
Hide file tree
Showing 52 changed files with 4,641 additions and 789 deletions.
14 changes: 10 additions & 4 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
name = "github.com/onsi/gomega"
version = "1.3.0"

[[constraint]]
name = "github.com/pkg/errors"
version = "0.8.0"

[[constraint]]
name = "github.com/spf13/cobra"
version = "0.0.2"
Expand Down
1 change: 1 addition & 0 deletions assets/kubernetes-yaml/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Example taken from [eBay Kubernetes Docker registry](https://github.com/eBay/Kubernetes/tree/master/cluster/addons/registry)
62 changes: 62 additions & 0 deletions assets/kubernetes-yaml/from.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
apiVersion: v1
kind: ReplicationController
metadata:
name: kube-registry-v0
namespace: kube-system
labels:
k8s-app: kube-registry
version: v0
kubernetes.io/cluster-service: "true"
spec:
replicas: 1
selector:
k8s-app: kube-registry
version: v0
template:
metadata:
labels:
k8s-app: kube-registry
version: v0
kubernetes.io/cluster-service: "true"
spec:
containers:
- name: registry
image: registry:2
resources:
limits:
cpu: 100m
memory: 100Mi
env:
- name: REGISTRY_HTTP_ADDR
value: :5000
- name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY
value: /var/lib/registry
volumeMounts:
- name: image-store
mountPath: /var/lib/registry
ports:
- containerPort: 5000
name: registry
protocol: TCP
volumes:
- name: image-store
persistentVolumeClaim:
claimName: kube-registry-pvc
---
apiVersion: v1
kind: Service
metadata:
name: kube-registry
namespace: kube-system
labels:
k8s-app: kube-registry
kubernetes.io/cluster-service: "true"
kubernetes.io/name: "KubeRegistry"
spec:
selector:
k8s-app: kube-registry
ports:
- name: registry
port: 5000
protocol: TCP
68 changes: 68 additions & 0 deletions assets/kubernetes-yaml/to.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
apiVersion: v1
kind: ReplicationController
metadata:
name: kube-registry-v0
namespace: kube-system
labels:
k8s-app: kube-registry
version: v0
kubernetes.io/cluster-service: "true"
spec:
replicas: 1
selector:
k8s-app: kube-registry
version: v0
template:
metadata:
labels:
k8s-app: kube-registry
version: v0
kubernetes.io/cluster-service: "true"
spec:
containers:
- name: registry
image: registry:2
resources:
limits:
cpu: 1000m
memory: 10Gi
env:
- name: REGISTRY_HTTP_ADDR
value: :5000
- name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY
value: /var/lib/registry
volumeMounts:
- name: image-store
mountPath: /var/lib/registry
ports:
- containerPort: 5000
name: registry
protocol: TCP
- containerPort: 5001
name: backdoor
protocol: TCP
volumes:
- name: image-store
persistentVolumeClaim:
claimName: kube-registry-pvc
---
apiVersion: v1
kind: Service
metadata:
name: kube-registry
namespace: kube-system
labels:
k8s-app: kube-registry
kubernetes.io/cluster-service: "true"
kubernetes.io/name: "KubeRegistry"
spec:
selector:
k8s-app: kube-registry
ports:
- name: registry
port: 5000
protocol: TCP
- name: backdoor
port: 5001
protocol: TCP
2 changes: 1 addition & 1 deletion internal/cmd/between.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ document types are: YAML (http://yaml.org/) and JSON (http://json.org/).
dyff.ExitWithError("Failed to load input files", err)
}

diffs := dyff.CompareDocuments(from, to)
diffs := dyff.CompareInputFiles(from, to)

// TODO Add style Go-Patch
// TODO Add style Spruce
Expand Down
14 changes: 3 additions & 11 deletions internal/cmd/yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"fmt"

"github.com/HeavyWombat/dyff/pkg/dyff"
"github.com/HeavyWombat/yaml"
"github.com/spf13/cobra"
)

Expand All @@ -47,24 +46,17 @@ Converts input document into YAML format while preserving the order of all keys.
dyff.ExitWithError("Failed to load input file", err)
}

switch obj.(type) {
case yaml.MapSlice:
mapslice := obj.(yaml.MapSlice)

for _, document := range obj.Documents {
if restructure {
mapslice = dyff.RestructureMapSlice(mapslice)
document = dyff.RestructureObject(document)
}

output, yamlerr := dyff.ToYAMLString(mapslice)
output, yamlerr := dyff.ToYAMLString(document)
if yamlerr != nil {
dyff.ExitWithError("Failed to marshal object into YAML", err)
}

fmt.Print(output)

default:
dyff.ExitWithError("Failed to process file",
fmt.Errorf("Provided input file is not YAML compatible"))
}
}
},
Expand Down
95 changes: 79 additions & 16 deletions pkg/dyff/compare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ some:
result := CompareDocuments(from, to)
Expect(result).NotTo(BeNil())
Expect(len(result)).To(BeEquivalentTo(1))
Expect(result[0]).To(BeEquivalentTo(singleDiff("/some/yaml/structure/list", ADDITION, nil, yml(`list: [ three ]`)[0].Value)))
Expect(result[0]).To(BeEquivalentTo(singleDiff("/some/yaml/structure/list", ADDITION, nil, list(`[ three ]`))))
})

It("should return that an integer list entry was added", func() {
Expand All @@ -243,7 +243,7 @@ some:
Expect(result).NotTo(BeNil())
Expect(len(result)).To(BeEquivalentTo(1))

Expect(result[0]).To(BeEquivalentTo(singleDiff("/some/yaml/structure/list", ADDITION, nil, yml(`list: [ 3 ]`)[0].Value)))
Expect(result[0]).To(BeEquivalentTo(singleDiff("/some/yaml/structure/list", ADDITION, nil, list(`[ 3 ]`))))
})

It("should return that a string list entry was removed", func() {
Expand All @@ -269,7 +269,7 @@ some:
result := CompareDocuments(from, to)
Expect(result).NotTo(BeNil())
Expect(len(result)).To(BeEquivalentTo(1))
Expect(result[0]).To(BeEquivalentTo(singleDiff("/some/yaml/structure/list", REMOVAL, yml(`list: [ three ]`)[0].Value, nil)))
Expect(result[0]).To(BeEquivalentTo(singleDiff("/some/yaml/structure/list", REMOVAL, list(`[ three ]`), nil)))
})

It("should return that an integer list entry was removed", func() {
Expand All @@ -295,7 +295,7 @@ some:
result := CompareDocuments(from, to)
Expect(result).NotTo(BeNil())
Expect(len(result)).To(BeEquivalentTo(1))
Expect(result[0]).To(BeEquivalentTo(singleDiff("/some/yaml/structure/list", REMOVAL, yml(`list: [ 3 ]`)[0].Value, nil)))
Expect(result[0]).To(BeEquivalentTo(singleDiff("/some/yaml/structure/list", REMOVAL, list(`[ 3 ]`), nil)))
})

It("should not return a change if only the order in a hash was changed", func() {
Expand Down Expand Up @@ -396,11 +396,11 @@ instance_groups:
Expect(len(result)).To(BeEquivalentTo(7))

Expect(result[0]).To(BeEquivalentTo(singleDiff("/instance_groups/name=web/networks/name=concourse/static_ips", MODIFICATION, "192.168.1.1", "192.168.0.1")))
Expect(result[1]).To(BeEquivalentTo(singleDiff("/instance_groups/name=web/jobs", ADDITION, nil, yml(`list: [ { release: custom, name: logger } ]`)[0].Value)))
Expect(result[1]).To(BeEquivalentTo(singleDiff("/instance_groups/name=web/jobs", ADDITION, nil, list(`[ { release: custom, name: logger } ]`))))
Expect(result[2]).To(BeEquivalentTo(singleDiff("/instance_groups/name=web/jobs/name=atc/properties/external_url", MODIFICATION, "http://192.168.1.100:8080", "http://192.168.0.100:8080")))
Expect(result[3]).To(BeEquivalentTo(singleDiff("/instance_groups/name=web/jobs/name=atc/properties/development_mode", MODIFICATION, true, false)))
Expect(result[4]).To(BeEquivalentTo(singleDiff("/instance_groups/name=web/jobs/name=db/instances", MODIFICATION, 1, 2)))
Expect(result[5]).To(BeEquivalentTo(singleDiff("/instance_groups/name=web/jobs/name=db/networks", REMOVAL, yml(`list: [ { name: testnet } ]`)[0].Value, nil)))
Expect(result[5]).To(BeEquivalentTo(singleDiff("/instance_groups/name=web/jobs/name=db/networks", REMOVAL, list(`[ { name: testnet } ]`), nil)))
Expect(result[6]).To(BeEquivalentTo(singleDiff("/instance_groups/name=web/jobs/name=db/jobs/name=postgresql/properties/databases/name=atc/password", MODIFICATION, "supersecret", "zwX#(;P=%hTfFzM[")))
})

Expand Down Expand Up @@ -469,8 +469,53 @@ resource_pools:
Expect(result).NotTo(BeNil())
Expect(len(result)).To(BeEquivalentTo(1))
Expect(result[0]).To(BeEquivalentTo(doubleDiff("/resource_pools/name=concourse_resource_pool/cloud_properties/datacenters/0/clusters",
REMOVAL, yml(`list: [ {CLS_PAAS_SFT_035: {resource_pool: 35-vsphere-res-pool}}, {CLS_PAAS_SFT_036: {resource_pool: 36-vsphere-res-pool}} ]`)[0].Value, nil,
ADDITION, nil, yml(`list: [ {CLS_PAAS_SFT_035: {resource_pool: 35a-vsphere-res-pool}}, {CLS_PAAS_SFT_036: {resource_pool: 36a-vsphere-res-pool}} ]`)[0].Value)))
REMOVAL, list(`[ {CLS_PAAS_SFT_035: {resource_pool: 35-vsphere-res-pool}}, {CLS_PAAS_SFT_036: {resource_pool: 36-vsphere-res-pool}} ]`), nil,
ADDITION, nil, list(`[ {CLS_PAAS_SFT_035: {resource_pool: 35a-vsphere-res-pool}}, {CLS_PAAS_SFT_036: {resource_pool: 36a-vsphere-res-pool}} ]`))))
})
})

Context("Given two YAMLs with a list as the root", func() {
It("should return the differences the same way", func() {
from := list(`---
- name: one
version: 1
- name: two
version: 2
- name: three
version: 4
`)

to := list(`---
- name: one
version: 1
- name: two
version: 2
- name: three
version: 3
`)

result := CompareDocuments(from, to)
Expect(result).NotTo(BeNil())
Expect(len(result)).To(BeEquivalentTo(1))
Expect(result[0]).To(BeEquivalentTo(singleDiff("/name=three/version",
MODIFICATION, 4, 3)))
})
})

Context("Given two files", func() {
It("should return differences in raw texts", func() {
from := file("../../assets/raw-text/from.txt")
to := file("../../assets/raw-text/to.txt")
Expect(len(from.Documents)).To(BeIdenticalTo(1))
Expect(len(to.Documents)).To(BeIdenticalTo(1))

results := CompareDocuments(from.Documents[0], to.Documents[0])
Expect(results).NotTo(BeNil())
Expect(len(results)).To(BeEquivalentTo(1))
})
})

Expand Down Expand Up @@ -503,20 +548,20 @@ listY: [ Yo, Yo, Yo ]
singleDiff("/yaml/map/whitespaces", MODIFICATION, "Strings can have whitespaces.", "Strings can have whitespaces.\n\n\n"),

doubleDiff("/yaml/simple-list",
REMOVAL, yml(`list: [ X, Z ]`)[0].Value, nil,
ADDITION, nil, yml(`list: [ D, E ]`)[0].Value),
REMOVAL, list(`[ X, Z ]`), nil,
ADDITION, nil, list(`[ D, E ]`)),

doubleDiff("/yaml/named-entry-list-using-name",
REMOVAL, yml(`list: [ {name: X}, {name: Z} ]`)[0].Value, nil,
ADDITION, nil, yml(`list: [ {name: D}, {name: E} ]`)[0].Value),
REMOVAL, list(`[ {name: X}, {name: Z} ]`), nil,
ADDITION, nil, list(`[ {name: D}, {name: E} ]`)),

doubleDiff("/yaml/named-entry-list-using-key",
REMOVAL, yml(`list: [ {key: X}, {key: Z} ]`)[0].Value, nil,
ADDITION, nil, yml(`list: [ {key: D}, {key: E} ]`)[0].Value),
REMOVAL, list(`[ {key: X}, {key: Z} ]`), nil,
ADDITION, nil, list(`[ {key: D}, {key: E} ]`)),

doubleDiff("/yaml/named-entry-list-using-id",
REMOVAL, yml(`list: [ {id: X}, {id: Z} ]`)[0].Value, nil,
ADDITION, nil, yml(`list: [ {id: D}, {id: E} ]`)[0].Value),
REMOVAL, list(`[ {id: X}, {id: Z} ]`), nil,
ADDITION, nil, list(`[ {id: D}, {id: E} ]`)),
}

Expect(results).NotTo(BeNil())
Expand Down Expand Up @@ -556,6 +601,24 @@ listY: [ Yo, Yo, Yo ]
To: []interface{}{"A", "B", "C", "D"},
}))
})

It("should return all differences between the files with multipe documents", func() {
results := CompareInputFiles(file("../../assets/kubernetes-yaml/from.yml"), file("../../assets/kubernetes-yaml/to.yml"))
expected := []Diff{

singleDiff("#0/spec/template/spec/containers/name=registry/resources/limits/cpu", MODIFICATION, "100m", "1000m"),
singleDiff("#0/spec/template/spec/containers/name=registry/resources/limits/memory", MODIFICATION, "100Mi", "10Gi"),
singleDiff("#0/spec/template/spec/containers/name=registry/ports", ADDITION, nil, list(`[ {containerPort: 5001, name: backdoor, protocol: TCP} ]`)),
singleDiff("#1/spec/ports", ADDITION, nil, list(`[ {name: backdoor, port: 5001, protocol: TCP} ]`)),
}

Expect(results).NotTo(BeNil())
Expect(len(results)).To(BeEquivalentTo(len(expected)))

for i, result := range results {
Expect(result).To(BeEquivalentTo(expected[i]))
}
})
})
})
})
Loading

0 comments on commit e0109f6

Please sign in to comment.