diff --git a/pkg/skaffold/instrumentation/meter.go b/pkg/skaffold/instrumentation/meter.go index 80af3c27960..6574fa0235f 100644 --- a/pkg/skaffold/instrumentation/meter.go +++ b/pkg/skaffold/instrumentation/meter.go @@ -66,5 +66,6 @@ func InitMeter(runCtx *runcontext.RunContext, config *latest.SkaffoldConfig) { meter.SyncType[yamltags.GetYamlTag(artifact.Sync)] = true } } + meter.Deployers = yamltags.GetYamlTags(config.Deploy.DeployType) meter.BuildArtifacts = len(config.Pipeline.Build.Artifacts) } diff --git a/pkg/skaffold/yamltags/tags.go b/pkg/skaffold/yamltags/tags.go index 24593010590..3f787f4260c 100644 --- a/pkg/skaffold/yamltags/tags.go +++ b/pkg/skaffold/yamltags/tags.go @@ -17,9 +17,12 @@ limitations under the License. package yamltags import ( + "bufio" + "bytes" "fmt" "reflect" "strings" + "unicode" "github.com/sirupsen/logrus" @@ -74,6 +77,39 @@ func GetYamlTag(value interface{}) string { return rawStr[:i] } +// GetYamlTags returns the tags of the non-nested fields of the given non-nil value +// If value interface{} is +// latest.DeployType{HelmDeploy: &HelmDeploy{...}, KustomizeDeploy: &KustomizeDeploy{...}} +// then this parses that interface as it's raw yaml: +// kubectl: +// manifests: +// - k8s/*.yaml +// kustomize: +// paths: +// - k8s/ +// and returns ["kubectl", "kustomize"] +// empty structs (e.g. latest.DeployType{}) when parsed look like "{}"" and so this function returns [] +func GetYamlTags(value interface{}) []string { + var tags []string + + buf, err := yaml.Marshal(value) + if err != nil { + logrus.Warnf("error marshaling %-v", value) + return tags + } + + r := bufio.NewScanner(bytes.NewBuffer(buf)) + for r.Scan() { + l := r.Text() + i := strings.Index(l, ":") + if !unicode.IsSpace(rune(l[0])) && l[0] != '-' && i >= 0 { + tags = append(tags, l[:i]) + } + } + + return tags +} + func processTags(yamltags string, val reflect.Value, parentStruct reflect.Value, field reflect.StructField) error { tags := strings.Split(yamltags, ",") for _, tag := range tags { diff --git a/pkg/skaffold/yamltags/tags_test.go b/pkg/skaffold/yamltags/tags_test.go index fa66239a0d0..037d4384fac 100644 --- a/pkg/skaffold/yamltags/tags_test.go +++ b/pkg/skaffold/yamltags/tags_test.go @@ -242,3 +242,57 @@ func TestGetYamlTag(t *testing.T) { }) } } + +func TestGetYamlTags(t *testing.T) { + a := "it's A" + b := "it's B" + c := "it's C" + + tests := []struct { + name string + yaml interface{} + expectedTags []string + }{ + { + name: "empty struct of pointers returns nil array", + yaml: abc{}, + expectedTags: nil, + }, + { + name: "subset of fields returns subset of tags", + yaml: abc{B: &b, C: &c}, + expectedTags: []string{"b", "c"}, + }, + { + name: "nested fields are not returned", + yaml: struct { + D *string `yaml:"d"` + Nested *abc `yaml:"nested"` + }{D: &a, Nested: &abc{A: &a, B: &b}}, + expectedTags: []string{"d", "nested"}, + }, + { + name: "only one field is returned if only one set", + yaml: abc{C: &c}, + expectedTags: []string{"c"}, + }, + { + name: "non-pointer fields are returned in empty struct", + yaml: struct{ A string }{}, + expectedTags: []string{"a"}, + }, + { + name: "array fields are not included", + yaml: struct { + List []abc `yaml:"abcs"` + }{List: []abc{{A: &a}, {B: &b}}}, + expectedTags: []string{"abcs"}, + }, + } + + for _, test := range tests { + testutil.Run(t, test.name, func(t *testutil.T) { + t.CheckDeepEqual(test.expectedTags, GetYamlTags(test.yaml)) + }) + } +}