From d088bfae3efbb484daff21f28e7ec4fa84fcbb5a Mon Sep 17 00:00:00 2001 From: Nan Zhong Date: Wed, 22 Jul 2020 12:33:55 -0400 Subject: [PATCH] apps: fix yaml spec handling and add support for log following (#842) * vendor: sigs.k8s.io/yaml * apps: fix handling of yaml spec files * apps: add support for following logs * vendor: bump github.com/digitalocean/godo@v1.42.0 * apps: include generic git source in test case * apps: update app mocks --- args.go | 4 +- commands/apps.go | 19 +++-- commands/apps_test.go | 85 ++++++++++++++++++- do/apps.go | 6 +- do/mocks/AppsService.go | 8 +- go.mod | 3 +- go.sum | 6 +- integration/apps_test.go | 3 + .../github.com/digitalocean/godo/CHANGELOG.md | 5 ++ vendor/github.com/digitalocean/godo/apps.go | 6 +- vendor/github.com/digitalocean/godo/godo.go | 2 +- .../github.com/digitalocean/godo/invoices.go | 1 + vendor/modules.txt | 5 +- vendor/sigs.k8s.io/yaml/.travis.yml | 15 ++-- vendor/sigs.k8s.io/yaml/OWNERS | 2 + vendor/sigs.k8s.io/yaml/README.md | 14 +-- vendor/sigs.k8s.io/yaml/go.mod | 8 ++ vendor/sigs.k8s.io/yaml/go.sum | 9 ++ vendor/sigs.k8s.io/yaml/yaml.go | 61 +++++++++++++ 19 files changed, 223 insertions(+), 39 deletions(-) create mode 100644 vendor/sigs.k8s.io/yaml/go.mod create mode 100644 vendor/sigs.k8s.io/yaml/go.sum diff --git a/args.go b/args.go index c14ee681a..71872936a 100644 --- a/args.go +++ b/args.go @@ -36,8 +36,10 @@ const ( ArgActionType = "action-type" // ArgAppSpec is a path to an app spec. ArgAppSpec = "spec" - // ArgAppLogType the type of log.. + // ArgAppLogType the type of log. ArgAppLogType = "type" + // ArgAppLogFollow follow logs. + ArgAppLogFollow = "follow" // ArgClusterName is a cluster name argument. ArgClusterName = "cluster-name" // ArgClusterVersionSlug is a cluster version argument. diff --git a/commands/apps.go b/commands/apps.go index 286c175be..91f7d8015 100644 --- a/commands/apps.go +++ b/commands/apps.go @@ -27,7 +27,7 @@ import ( "github.com/digitalocean/doctl/commands/displayers" "github.com/digitalocean/godo" "github.com/spf13/cobra" - "gopkg.in/yaml.v2" + "sigs.k8s.io/yaml" ) // Apps creates the apps command. @@ -158,6 +158,7 @@ Three types of logs are supported and can be configured with --`+doctl.ArgAppLog aliasOpt("l"), ) AddStringFlag(logs, doctl.ArgAppLogType, "", strings.ToLower(string(godo.AppLogTypeRun)), "The type of logs.") + AddBoolFlag(logs, doctl.ArgAppLogFollow, "f", false, "Follow logs as they are emitted.") return cmd } @@ -349,8 +350,12 @@ func RunAppsGetLogs(c *CmdConfig) error { default: return fmt.Errorf("Invalid log type %s", logTypeStr) } + logFollow, err := c.Doit.GetBool(c.NS, doctl.ArgAppLogFollow) + if err != nil { + return err + } - logs, err := c.Apps().GetLogs(appID, deploymentID, component, logType) + logs, err := c.Apps().GetLogs(appID, deploymentID, component, logType, logFollow) if err != nil { return err } @@ -379,13 +384,13 @@ func RunAppsGetLogs(c *CmdConfig) error { } func parseAppSpec(spec []byte) (*godo.AppSpec, error) { - var appSpec godo.AppSpec - err := json.Unmarshal(spec, &appSpec) - if err == nil { - return &appSpec, nil + jsonSpec, err := yaml.YAMLToJSON(spec) + if err != nil { + return nil, err } - err = yaml.Unmarshal(spec, &appSpec) + var appSpec godo.AppSpec + err = json.Unmarshal(jsonSpec, &appSpec) if err == nil { return &appSpec, nil } diff --git a/commands/apps_test.go b/commands/apps_test.go index fa99892c5..e2b548e50 100644 --- a/commands/apps_test.go +++ b/commands/apps_test.go @@ -10,6 +10,7 @@ import ( "github.com/digitalocean/doctl" "github.com/digitalocean/godo" "github.com/google/uuid" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -284,13 +285,95 @@ func TestRunAppsGetLogs(t *testing.T) { for typeStr, logType := range types { withTestClient(t, func(config *CmdConfig, tm *tcMocks) { - tm.apps.EXPECT().GetLogs(appID, deploymentID, component, logType).Times(1).Return(&godo.AppLogs{LiveURL: "https://proxy-apps-prod-ams3-001.ondigitalocean.app/?token=..."}, nil) + tm.apps.EXPECT().GetLogs(appID, deploymentID, component, logType, true).Times(1).Return(&godo.AppLogs{LiveURL: "https://proxy-apps-prod-ams3-001.ondigitalocean.app/?token=..."}, nil) config.Args = append(config.Args, appID, deploymentID, component) config.Doit.Set(config.NS, doctl.ArgAppLogType, typeStr) + config.Doit.Set(config.NS, doctl.ArgAppLogFollow, true) err := RunAppsGetLogs(config) require.NoError(t, err) }) } } + +func Test_parseAppSpec(t *testing.T) { + expectedSpec := &godo.AppSpec{ + Name: "test", + Services: []godo.AppServiceSpec{ + { + Name: "web", + GitHub: godo.GitHubSourceSpec{ + Repo: "digitalocean/sample-golang", + Branch: "master", + }, + }, + }, + StaticSites: []godo.AppStaticSiteSpec{ + { + Name: "static", + Git: godo.GitSourceSpec{ + RepoCloneURL: "git@github.com:digitalocean/sample-gatsby.git", + Branch: "master", + }, + Routes: []godo.AppRouteSpec{ + {Path: "/static"}, + }, + }, + }, + } + + t.Run("json", func(t *testing.T) { + spec, err := parseAppSpec([]byte(`{ + "name": "test", + "services": [ + { + "name": "web", + "github": { + "repo": "digitalocean/sample-golang", + "branch": "master" + } + } + ], + "static_sites": [ + { + "name": "static", + "git": { + "repo_clone_url": "git@github.com:digitalocean/sample-gatsby.git", + "branch": "master" + }, + "routes": [ + { + "path": "/static" + } + ] + } + ] +}`)) + require.NoError(t, err) + assert.Equal(t, expectedSpec, spec) + }) + t.Run("yaml", func(t *testing.T) { + spec, err := parseAppSpec([]byte(` +name: test +services: +- name: web + github: + repo: digitalocean/sample-golang + branch: master +static_sites: +- name: static + git: + repo_clone_url: git@github.com:digitalocean/sample-gatsby.git + branch: master + routes: + - path: /static +`)) + require.NoError(t, err) + assert.Equal(t, expectedSpec, spec) + }) + t.Run("invalid", func(t *testing.T) { + _, err := parseAppSpec([]byte("invalid spec")) + require.Error(t, err) + }) +} diff --git a/do/apps.go b/do/apps.go index 19f7ea9fc..f6bc1428a 100644 --- a/do/apps.go +++ b/do/apps.go @@ -31,7 +31,7 @@ type AppsService interface { GetDeployment(appID, deploymentID string) (*godo.Deployment, error) ListDeployments(appID string) ([]*godo.Deployment, error) - GetLogs(appID, deploymentID, component string, logType godo.AppLogType) (*godo.AppLogs, error) + GetLogs(appID, deploymentID, component string, logType godo.AppLogType, follow bool) (*godo.AppLogs, error) } type appsService struct { @@ -110,8 +110,8 @@ func (s *appsService) ListDeployments(appID string) ([]*godo.Deployment, error) return deployments, nil } -func (s *appsService) GetLogs(appID, deploymentID, component string, logType godo.AppLogType) (*godo.AppLogs, error) { - logs, _, err := s.client.Apps.GetLogs(s.ctx, appID, deploymentID, component, logType) +func (s *appsService) GetLogs(appID, deploymentID, component string, logType godo.AppLogType, follow bool) (*godo.AppLogs, error) { + logs, _, err := s.client.Apps.GetLogs(s.ctx, appID, deploymentID, component, logType, follow) if err != nil { return nil, err } diff --git a/do/mocks/AppsService.go b/do/mocks/AppsService.go index 43afeb14e..cafcc5a99 100644 --- a/do/mocks/AppsService.go +++ b/do/mocks/AppsService.go @@ -153,16 +153,16 @@ func (mr *MockAppsServiceMockRecorder) ListDeployments(appID interface{}) *gomoc } // GetLogs mocks base method. -func (m *MockAppsService) GetLogs(appID, deploymentID, component string, logType godo.AppLogType) (*godo.AppLogs, error) { +func (m *MockAppsService) GetLogs(appID, deploymentID, component string, logType godo.AppLogType, follow bool) (*godo.AppLogs, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetLogs", appID, deploymentID, component, logType) + ret := m.ctrl.Call(m, "GetLogs", appID, deploymentID, component, logType, follow) ret0, _ := ret[0].(*godo.AppLogs) ret1, _ := ret[1].(error) return ret0, ret1 } // GetLogs indicates an expected call of GetLogs. -func (mr *MockAppsServiceMockRecorder) GetLogs(appID, deploymentID, component, logType interface{}) *gomock.Call { +func (mr *MockAppsServiceMockRecorder) GetLogs(appID, deploymentID, component, logType, follow interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogs", reflect.TypeOf((*MockAppsService)(nil).GetLogs), appID, deploymentID, component, logType) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogs", reflect.TypeOf((*MockAppsService)(nil).GetLogs), appID, deploymentID, component, logType, follow) } diff --git a/go.mod b/go.mod index 097bf5a0a..ccb746b18 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb // indirect github.com/cpuguy83/go-md2man v1.0.10 // indirect github.com/creack/pty v1.1.7 - github.com/digitalocean/godo v1.41.0 + github.com/digitalocean/godo v1.42.0 github.com/docker/cli v0.0.0-20200622130859-87db43814b48 github.com/docker/docker v17.12.0-ce-rc1.0.20200531234253-77e06fda0c94+incompatible // indirect github.com/docker/docker-credential-helpers v0.6.3 // indirect @@ -46,6 +46,7 @@ require ( k8s.io/api v0.17.0 k8s.io/apimachinery v0.17.0 k8s.io/client-go v0.17.0 + sigs.k8s.io/yaml v1.2.0 ) replace github.com/stretchr/objx => github.com/stretchr/objx v0.2.0 diff --git a/go.sum b/go.sum index a8b0419b6..b13c4d913 100644 --- a/go.sum +++ b/go.sum @@ -56,8 +56,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/digitalocean/godo v1.41.0 h1:WYy7MIVVhTMZUNB+UA3irl2V9FyDJeDttsifYyn7jYA= -github.com/digitalocean/godo v1.41.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU= +github.com/digitalocean/godo v1.42.0 h1:xQlEFLhQ1zZUryJAfiWb8meLPPCWnLO901U5Imhh0Mc= +github.com/digitalocean/godo v1.42.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU= github.com/docker/cli v0.0.0-20200622130859-87db43814b48 h1:AC8qbhi/SjYf4iN2W3jSsofZGHWPjG8pjf5P143KUM8= github.com/docker/cli v0.0.0-20200622130859-87db43814b48/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v17.12.0-ce-rc1.0.20200531234253-77e06fda0c94+incompatible h1:PmGHHCZ43l6h8aZIi+Xa+z1SWe4dFImd5EK3TNp1jlo= @@ -443,3 +443,5 @@ rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/integration/apps_test.go b/integration/apps_test.go index 955fbfa38..002150441 100644 --- a/integration/apps_test.go +++ b/integration/apps_test.go @@ -537,6 +537,7 @@ var _ = suite("apps/get-logs", func(t *testing.T, when spec.G, it spec.S) { } assert.Equal(t, "RUN", req.URL.Query().Get("type")) + assert.Equal(t, "true", req.URL.Query().Get("follow")) json.NewEncoder(w).Encode(&godo.AppLogs{LiveURL: logsURL}) case "/fake-logs": @@ -562,6 +563,8 @@ var _ = suite("apps/get-logs", func(t *testing.T, when spec.G, it spec.S) { testAppUUID, testDeploymentUUID, "service", + "--type=run", + "-f", ) output, err := cmd.CombinedOutput() diff --git a/vendor/github.com/digitalocean/godo/CHANGELOG.md b/vendor/github.com/digitalocean/godo/CHANGELOG.md index a2496cdc5..729e7bb9d 100644 --- a/vendor/github.com/digitalocean/godo/CHANGELOG.md +++ b/vendor/github.com/digitalocean/godo/CHANGELOG.md @@ -1,5 +1,10 @@ # Change Log +## [v1.42.0] - 2020-07-22 + +- #357 invoices: add category to InvoiceItem - @rbutler +- #358 apps: add support for following logs - @nanzhong + ## [v1.41.0] - 2020-07-17 - #355 kubernetes: Add support for surge upgrades - @varshavaradarajan diff --git a/vendor/github.com/digitalocean/godo/apps.go b/vendor/github.com/digitalocean/godo/apps.go index 6bf9fc9b1..245971603 100644 --- a/vendor/github.com/digitalocean/godo/apps.go +++ b/vendor/github.com/digitalocean/godo/apps.go @@ -36,7 +36,7 @@ type AppsService interface { ListDeployments(ctx context.Context, appID string, opts *ListOptions) ([]*Deployment, *Response, error) CreateDeployment(ctx context.Context, appID string) (*Deployment, *Response, error) - GetLogs(ctx context.Context, appID, deploymentID, component string, logType AppLogType) (*AppLogs, *Response, error) + GetLogs(ctx context.Context, appID, deploymentID, component string, logType AppLogType, follow bool) (*AppLogs, *Response, error) } // App represents an app. @@ -263,8 +263,8 @@ func (s *AppsServiceOp) CreateDeployment(ctx context.Context, appID string) (*De } // GetLogs retrieves app logs. -func (s *AppsServiceOp) GetLogs(ctx context.Context, appID, deploymentID, component string, logType AppLogType) (*AppLogs, *Response, error) { - url := fmt.Sprintf("%s/%s/deployments/%s/components/%s/logs?type=%s", appsBasePath, appID, deploymentID, component, logType) +func (s *AppsServiceOp) GetLogs(ctx context.Context, appID, deploymentID, component string, logType AppLogType, follow bool) (*AppLogs, *Response, error) { + url := fmt.Sprintf("%s/%s/deployments/%s/components/%s/logs?type=%s&follow=%t", appsBasePath, appID, deploymentID, component, logType, follow) req, err := s.client.NewRequest(ctx, http.MethodGet, url, nil) if err != nil { return nil, nil, err diff --git a/vendor/github.com/digitalocean/godo/godo.go b/vendor/github.com/digitalocean/godo/godo.go index 9bddb3cba..c118533c7 100644 --- a/vendor/github.com/digitalocean/godo/godo.go +++ b/vendor/github.com/digitalocean/godo/godo.go @@ -19,7 +19,7 @@ import ( ) const ( - libraryVersion = "1.41.0" + libraryVersion = "1.42.0" defaultBaseURL = "https://api.digitalocean.com/" userAgent = "godo/" + libraryVersion mediaType = "application/json" diff --git a/vendor/github.com/digitalocean/godo/invoices.go b/vendor/github.com/digitalocean/godo/invoices.go index cc111f871..abc9d2de6 100644 --- a/vendor/github.com/digitalocean/godo/invoices.go +++ b/vendor/github.com/digitalocean/godo/invoices.go @@ -49,6 +49,7 @@ type InvoiceItem struct { StartTime time.Time `json:"start_time"` EndTime time.Time `json:"end_time"` ProjectName string `json:"project_name"` + Category string `json:"category"` } // InvoiceList contains a paginated list of all of a customer's invoices. diff --git a/vendor/modules.txt b/vendor/modules.txt index 57d7df6c5..a073353f8 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -18,7 +18,7 @@ github.com/cpuguy83/go-md2man/md2man github.com/creack/pty # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew -# github.com/digitalocean/godo v1.41.0 +# github.com/digitalocean/godo v1.42.0 ## explicit github.com/digitalocean/godo github.com/digitalocean/godo/util @@ -347,7 +347,8 @@ k8s.io/client-go/util/keyutil k8s.io/klog # k8s.io/utils v0.0.0-20191114184206-e782cd3c129f k8s.io/utils/integer -# sigs.k8s.io/yaml v1.1.0 +# sigs.k8s.io/yaml v1.2.0 +## explicit sigs.k8s.io/yaml # github.com/stretchr/objx => github.com/stretchr/objx v0.2.0 # golang.org/x/crypto => golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a diff --git a/vendor/sigs.k8s.io/yaml/.travis.yml b/vendor/sigs.k8s.io/yaml/.travis.yml index 03ddc7318..d20e23eff 100644 --- a/vendor/sigs.k8s.io/yaml/.travis.yml +++ b/vendor/sigs.k8s.io/yaml/.travis.yml @@ -1,14 +1,13 @@ language: go dist: xenial go: - - 1.9.x - - 1.10.x - - 1.11.x + - 1.12.x + - 1.13.x script: - - go get -t -v ./... - - diff -u <(echo -n) <(gofmt -d .) + - diff -u <(echo -n) <(gofmt -d *.go) - diff -u <(echo -n) <(golint $(go list -e ./...) | grep -v YAMLToJSON) - - go tool vet . - - go test -v -race ./... + - GO111MODULE=on go vet . + - GO111MODULE=on go test -v -race ./... + - git diff --exit-code install: - - go get golang.org/x/lint/golint + - GO111MODULE=off go get golang.org/x/lint/golint diff --git a/vendor/sigs.k8s.io/yaml/OWNERS b/vendor/sigs.k8s.io/yaml/OWNERS index 11ad7ce1a..325b40b07 100644 --- a/vendor/sigs.k8s.io/yaml/OWNERS +++ b/vendor/sigs.k8s.io/yaml/OWNERS @@ -1,3 +1,5 @@ +# See the OWNERS docs at https://go.k8s.io/owners + approvers: - dims - lavalamp diff --git a/vendor/sigs.k8s.io/yaml/README.md b/vendor/sigs.k8s.io/yaml/README.md index 0200f75b4..5a651d916 100644 --- a/vendor/sigs.k8s.io/yaml/README.md +++ b/vendor/sigs.k8s.io/yaml/README.md @@ -1,12 +1,14 @@ # YAML marshaling and unmarshaling support for Go -[![Build Status](https://travis-ci.org/ghodss/yaml.svg)](https://travis-ci.org/ghodss/yaml) +[![Build Status](https://travis-ci.org/kubernetes-sigs/yaml.svg)](https://travis-ci.org/kubernetes-sigs/yaml) + +kubernetes-sigs/yaml is a permanent fork of [ghodss/yaml](https://github.com/ghodss/yaml). ## Introduction A wrapper around [go-yaml](https://github.com/go-yaml/yaml) designed to enable a better way of handling YAML when marshaling to and from structs. -In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/). +In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://web.archive.org/web/20190603050330/http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/). ## Compatibility @@ -32,13 +34,13 @@ GOOD: To install, run: ``` -$ go get github.com/ghodss/yaml +$ go get sigs.k8s.io/yaml ``` And import using: ``` -import "github.com/ghodss/yaml" +import "sigs.k8s.io/yaml" ``` Usage is very similar to the JSON library: @@ -49,7 +51,7 @@ package main import ( "fmt" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" ) type Person struct { @@ -93,7 +95,7 @@ package main import ( "fmt" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" ) func main() { diff --git a/vendor/sigs.k8s.io/yaml/go.mod b/vendor/sigs.k8s.io/yaml/go.mod new file mode 100644 index 000000000..7224f3497 --- /dev/null +++ b/vendor/sigs.k8s.io/yaml/go.mod @@ -0,0 +1,8 @@ +module sigs.k8s.io/yaml + +go 1.12 + +require ( + github.com/davecgh/go-spew v1.1.1 + gopkg.in/yaml.v2 v2.2.8 +) diff --git a/vendor/sigs.k8s.io/yaml/go.sum b/vendor/sigs.k8s.io/yaml/go.sum new file mode 100644 index 000000000..76e49483a --- /dev/null +++ b/vendor/sigs.k8s.io/yaml/go.sum @@ -0,0 +1,9 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/sigs.k8s.io/yaml/yaml.go b/vendor/sigs.k8s.io/yaml/yaml.go index 024596112..efbc535d4 100644 --- a/vendor/sigs.k8s.io/yaml/yaml.go +++ b/vendor/sigs.k8s.io/yaml/yaml.go @@ -317,3 +317,64 @@ func convertToJSONableObject(yamlObj interface{}, jsonTarget *reflect.Value) (in return yamlObj, nil } } + +// JSONObjectToYAMLObject converts an in-memory JSON object into a YAML in-memory MapSlice, +// without going through a byte representation. A nil or empty map[string]interface{} input is +// converted to an empty map, i.e. yaml.MapSlice(nil). +// +// interface{} slices stay interface{} slices. map[string]interface{} becomes yaml.MapSlice. +// +// int64 and float64 are down casted following the logic of github.com/go-yaml/yaml: +// - float64s are down-casted as far as possible without data-loss to int, int64, uint64. +// - int64s are down-casted to int if possible without data-loss. +// +// Big int/int64/uint64 do not lose precision as in the json-yaml roundtripping case. +// +// string, bool and any other types are unchanged. +func JSONObjectToYAMLObject(j map[string]interface{}) yaml.MapSlice { + if len(j) == 0 { + return nil + } + ret := make(yaml.MapSlice, 0, len(j)) + for k, v := range j { + ret = append(ret, yaml.MapItem{Key: k, Value: jsonToYAMLValue(v)}) + } + return ret +} + +func jsonToYAMLValue(j interface{}) interface{} { + switch j := j.(type) { + case map[string]interface{}: + if j == nil { + return interface{}(nil) + } + return JSONObjectToYAMLObject(j) + case []interface{}: + if j == nil { + return interface{}(nil) + } + ret := make([]interface{}, len(j)) + for i := range j { + ret[i] = jsonToYAMLValue(j[i]) + } + return ret + case float64: + // replicate the logic in https://github.com/go-yaml/yaml/blob/51d6538a90f86fe93ac480b35f37b2be17fef232/resolve.go#L151 + if i64 := int64(j); j == float64(i64) { + if i := int(i64); i64 == int64(i) { + return i + } + return i64 + } + if ui64 := uint64(j); j == float64(ui64) { + return ui64 + } + return j + case int64: + if i := int(j); j == int64(i) { + return i + } + return j + } + return j +}