Skip to content
Open
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
50 changes: 44 additions & 6 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"io/ioutil"
"os"
"os/exec"
"strings"
"unicode"

"github.com/ghodss/yaml"
Expand Down Expand Up @@ -145,26 +146,63 @@ func isJSON(s []byte) bool {
return bytes.HasPrefix(bytes.TrimLeftFunc(s, unicode.IsSpace), []byte{'{'})
}

func hasDashes(s []byte) bool {
return strings.Contains(string(s), "\n---\n")
}

// NeatYAMLOrJSON converts 'in' to json if needed, invokes neat, and converts back if needed according the the outputFormat argument: yaml/json/same
func NeatYAMLOrJSON(in []byte, outputFormat string) (out []byte, err error) {
var injson, outjson string
var injson, outjson, outyaml string
var hasDocs = false
itsYaml := !isJSON(in)
if itsYaml {
injsonbytes, err := yaml.YAMLToJSON(in)
if err != nil {
return nil, fmt.Errorf("error converting from yaml to json : %v", err)
hasDocs = hasDashes(in)
if hasDocs {
documents := strings.Split(string(in), "\n---\n")
for i, doc := range documents {
injsonbytes, err := yaml.YAMLToJSON([]byte(doc))
if err != nil {
return nil, fmt.Errorf("[Doc n.%d]: error converting from yaml to json: %v", i+1, err)
}
res, err := Neat(string(injsonbytes))
if err != nil {
return nil, fmt.Errorf("error from NeatPod: %v", err)
}
outjson += res + "\n"
if outputFormat == "yaml" || (outputFormat == "same" && itsYaml) {
oyaml, err := yaml.JSONToYAML([]byte(res))
if err != nil {
return nil, fmt.Errorf("error converting from json to yaml : %v", err)
}
if i == 0 {
outyaml += string(oyaml)
} else {
outyaml += "---\n" + string(oyaml)
}
}
}
} else {
injsonbytes, err := yaml.YAMLToJSON([]byte(in))
if err != nil {
return nil, fmt.Errorf("error converting from yaml to json: %v", err)
}
injson = string(injsonbytes)
outjson, err = Neat(injson)
}
injson = string(injsonbytes)
} else {
injson = string(in)
outjson, err = Neat(injson)
}

outjson, err = Neat(injson)
if err != nil {
return nil, fmt.Errorf("error neating : %v", err)
}

if outputFormat == "yaml" || (outputFormat == "same" && itsYaml) {
if hasDocs {
out = []byte(outyaml)
return
}
out, err = yaml.JSONToYAML([]byte(outjson))
if err != nil {
return nil, fmt.Errorf("error converting from json to yaml : %v", err)
Expand Down
19 changes: 18 additions & 1 deletion cmd/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,12 @@ func TestRootCmd(t *testing.T) {
if err != nil {
t.Errorf("error readin test data file %s: %v", resourceDataYAMLPath, err)
}

resourceDataMultiYAMLPath := "../test/fixtures/multidoc-raw.yaml"
resourceDataMultiYAMLBytes, err := ioutil.ReadFile(resourceDataMultiYAMLPath)
resourceDataMultiYAML := string(resourceDataMultiYAMLBytes)
if err != nil {
t.Errorf("error readin test data file %s: %v", resourceDataMultiYAMLPath, err)
}
testcases := []struct {
args []string
stdin string
Expand All @@ -64,6 +69,12 @@ func TestRootCmd(t *testing.T) {
assertError: assertErrorNil,
expOut: "apiVersion",
},
{
args: []string{},
stdin: resourceDataMultiYAML,
assertError: assertErrorNil,
expOut: "apiVersion",
},
{
args: []string{"-f", "-"},
stdin: resourceDataJSON,
Expand All @@ -85,6 +96,12 @@ func TestRootCmd(t *testing.T) {
assertError: assertErrorNil,
expOut: "apiVersion",
},
{
args: []string{"-f", resourceDataMultiYAMLPath},
stdin: "",
assertError: assertErrorNil,
expOut: "apiVersion",
},
{
args: []string{"-f", resourceDataYAMLPath},
stdin: "",
Expand Down
159 changes: 159 additions & 0 deletions test/fixtures/multidoc-raw.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
apiVersion: v1
data:
.dockerconfigjson: eyJhdXRocyI6eyJteXJlZ2lzdHJ5LnRlc3QiOnsidXNlcm5hbWUiOiJ1c2VyIiwicGFzc3dvcmQiOiJwYXNzIiwiZW1haWwiOiJ1c2VyQGVtYWlsLnRlc3QiLCJhdXRoIjoiZFhObGNqcHdZWE56In19fQ==
kind: Secret
metadata:
creationTimestamp: "2020-04-03T05:45:54Z"
name: myreg
namespace: default
resourceVersion: "3376"
selfLink: /api/v1/namespaces/default/secrets/myreg
uid: 62a187fd-756e-11ea-b27b-0242ac11002d
type: kubernetes.io/dockerconfigjson
---
apiVersion: v1
kind: Service
metadata:
creationTimestamp: "2019-04-24T20:12:14Z"
name: myappservice
namespace: default
resourceVersion: "187503"
selfLink: /api/v1/namespaces/default/services/myappservice
uid: 409de7fb-66cd-11e9-b6fa-0800271788ca
spec:
clusterIP: None
ports:
- port: 2222
protocol: TCP
targetPort: 2222
selector:
name: myapp
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
---
apiVersion: v1
kind: PersistentVolume
metadata:
annotations:
hostPathProvisionerIdentity: 7de69121-4d7a-11e9-8684-0800271788ca
pv.kubernetes.io/provisioned-by: k8s.io/minikube-hostpath
creationTimestamp: "2019-03-23T14:52:51Z"
finalizers:
- kubernetes.io/pv-protection
name: pvc-54fad2fe-4d7b-11e9-9172-0800271788ca
resourceVersion: "186863"
selfLink: /api/v1/persistentvolumes/pvc-54fad2fe-4d7b-11e9-9172-0800271788ca
uid: 5527dbad-4d7b-11e9-9172-0800271788ca
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 2Gi
claimRef:
apiVersion: v1
kind: PersistentVolumeClaim
name: prom-prometheus-alertmanager
namespace: default
resourceVersion: "860"
uid: 54fad2fe-4d7b-11e9-9172-0800271788ca
hostPath:
path: /tmp/hostpath-provisioner/pvc-54fad2fe-4d7b-11e9-9172-0800271788ca
type: ""
persistentVolumeReclaimPolicy: Delete
storageClassName: standard
volumeMode: Filesystem
status:
phase: Released
---
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2019-04-24T19:55:27Z"
labels:
name: myapp
name: myapp
namespace: default
resourceVersion: "274103"
selfLink: /api/v1/namespaces/default/pods/myapp
uid: e8330f3c-66ca-11e9-b6fa-0800271788ca
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: myapp
ports:
- containerPort: 1234
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-nmshj
readOnly: true
dnsPolicy: ClusterFirst
enableServiceLinks: true
nodeName: minikube
priority: 0
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- name: default-token-nmshj
secret:
defaultMode: 420
secretName: default-token-nmshj
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2019-04-24T19:55:27Z"
status: "True"
type: Initialized
- lastProbeTime: null
lastTransitionTime: "2019-07-06T18:41:25Z"
status: "True"
type: Ready
- lastProbeTime: null
lastTransitionTime: "2019-07-06T18:41:25Z"
status: "True"
type: ContainersReady
- lastProbeTime: null
lastTransitionTime: "2019-04-24T19:55:27Z"
status: "True"
type: PodScheduled
containerStatuses:
- containerID: docker://92d7dc7a851453c2f1e75c4af42a9e72fea50127fede62dfbd5fbb6fb0481fcc
image: nginx:latest
imageID: docker-pullable://nginx@sha256:96fb261b66270b900ea5a2c17a26abbfabe95506e73c3a3c65869a6dbe83223a
lastState:
terminated:
containerID: docker://288fc0a2b98708d6a4661f59c54c4ae366c1acea642f000ba9615932dbff411f
exitCode: 0
finishedAt: "2019-07-04T08:17:20Z"
reason: Completed
startedAt: "2019-07-03T05:55:39Z"
name: myapp
ready: true
restartCount: 3
state:
running:
startedAt: "2019-07-06T18:41:25Z"
hostIP: 10.0.2.15
phase: Running
podIP: 172.17.0.2
qosClass: BestEffort
startTime: "2019-04-24T19:55:27Z"