diff --git a/cmd/config/internal/commands/cmdcreatesetter.go b/cmd/config/internal/commands/cmdcreatesetter.go index 4dc9c5641..78ebb2d27 100644 --- a/cmd/config/internal/commands/cmdcreatesetter.go +++ b/cmd/config/internal/commands/cmdcreatesetter.go @@ -34,6 +34,8 @@ func NewCreateSetterRunner(parent string) *CreateSetterRunner { "kind of the Resource on which to create the setter.") set.Flags().StringVar(&r.Set.SetPartialField.Type, "type", "", "valid OpenAPI field type -- e.g. integer,boolean,string.") + set.Flags().BoolVar(&r.Set.SetPartialField.Partial, "partial", false, + "create a partial setter for only part of the field value.") fixDocs(parent, set) set.MarkFlagRequired("type") set.MarkFlagRequired("field") diff --git a/kyaml/fieldmeta/fieldmeta.go b/kyaml/fieldmeta/fieldmeta.go index 3a9742654..3ed5fc73c 100644 --- a/kyaml/fieldmeta/fieldmeta.go +++ b/kyaml/fieldmeta/fieldmeta.go @@ -22,7 +22,8 @@ type FieldMeta struct { type XKustomize struct { SetBy string `yaml:"setBy,omitempty" json:"setBy,omitempty"` - PartialFieldSetters []PartialFieldSetter `yaml:"partialFieldSetters" json:"partialFieldSetters"` + PartialFieldSetters []PartialFieldSetter `yaml:"partialSetters,omitempty" json:"partialSetters,omitempty"` + FieldSetter *PartialFieldSetter `yaml:"setter,omitempty" json:"setter,omitempty"` } // PartialFieldSetter defines how to set part of a field rather than the full field diff --git a/kyaml/setters/addyaml.go b/kyaml/setters/addyaml.go index 22aec3696..0a70fa84a 100644 --- a/kyaml/setters/addyaml.go +++ b/kyaml/setters/addyaml.go @@ -29,6 +29,9 @@ type customFieldSetter struct { Type string + // Partial will create a partial setter if set to true + Partial bool + // currentFieldName is the name of the current field being processed currentFieldName string } @@ -66,11 +69,6 @@ func (m *customFieldSetter) Filter(object *yaml.RNode) (*yaml.RNode, error) { } func (m *customFieldSetter) create(field *yaml.RNode) error { - // doesn't match the supplied value - if !strings.Contains(field.YNode().Value, m.Setter.Value) { - return nil - } - fm := fieldmeta.FieldMeta{} if err := fm.Read(field); err != nil { return errors.Wrap(err) @@ -83,20 +81,35 @@ func (m *customFieldSetter) create(field *yaml.RNode) error { fm.Extensions.SetBy = m.SetBy fm.Schema.Type = []string{m.Type} - found := false - for i := range fm.Extensions.PartialFieldSetters { - s := fm.Extensions.PartialFieldSetters[i] - if s.Name == m.Setter.Name { - // update the setter if we find it - found = true - fm.Extensions.PartialFieldSetters[i] = m.Setter - break + if !m.Partial { + // doesn't match the supplied value + if field.YNode().Value != m.Setter.Value { + return nil + } + // full setter + fm.Extensions.FieldSetter = &m.Setter + fm.Extensions.PartialFieldSetters = nil + } else { + // doesn't match the supplied value + if !strings.Contains(field.YNode().Value, m.Setter.Value) { + return nil + } + found := false + for i := range fm.Extensions.PartialFieldSetters { + s := fm.Extensions.PartialFieldSetters[i] + if s.Name == m.Setter.Name { + // update the setter if we find it + found = true + fm.Extensions.PartialFieldSetters[i] = m.Setter + break + } + } + if !found { + // add the setter if it wasn't found + fm.Extensions.PartialFieldSetters = append(fm.Extensions.PartialFieldSetters, m.Setter) } } - if !found { - // add the setter if it wasn't found - fm.Extensions.PartialFieldSetters = append(fm.Extensions.PartialFieldSetters, m.Setter) - } + if err := fm.Write(field); err != nil { return errors.Wrap(err) } diff --git a/kyaml/setters/dokio.go b/kyaml/setters/dokio.go index 182a73122..32b9a8f9d 100644 --- a/kyaml/setters/dokio.go +++ b/kyaml/setters/dokio.go @@ -30,7 +30,7 @@ type PerformSetters struct { func (s *PerformSetters) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { for i := range input { - p := &partialFieldSetter{ + p := &fieldSetter{ Name: s.Name, Value: s.Value, Description: s.Description, diff --git a/kyaml/setters/doyaml.go b/kyaml/setters/doyaml.go index 69d64acc2..dd35fea61 100644 --- a/kyaml/setters/doyaml.go +++ b/kyaml/setters/doyaml.go @@ -11,10 +11,10 @@ import ( "sigs.k8s.io/kustomize/kyaml/yaml" ) -var _ yaml.Filter = &partialFieldSetter{} +var _ yaml.Filter = &fieldSetter{} -// partialFieldSetter sets part of a field value. -type partialFieldSetter struct { +// fieldSetter sets part or all of a field value. +type fieldSetter struct { // Name is the name of the setter to perform. Name string @@ -32,7 +32,7 @@ type partialFieldSetter struct { } // Filter implements yaml.Filter -func (fs *partialFieldSetter) Filter(object *yaml.RNode) (*yaml.RNode, error) { +func (fs *fieldSetter) Filter(object *yaml.RNode) (*yaml.RNode, error) { switch object.YNode().Kind { case yaml.DocumentNode: // Document is the root of the object and always contains 1 node @@ -49,7 +49,7 @@ func (fs *partialFieldSetter) Filter(object *yaml.RNode) (*yaml.RNode, error) { }) case yaml.ScalarNode: // Check if there is a setter matching the name - s, f, err := fs.findPartialSetter(object) + s, f, partial, err := fs.findSetter(object) if err != nil { return nil, err } @@ -58,19 +58,19 @@ func (fs *partialFieldSetter) Filter(object *yaml.RNode) (*yaml.RNode, error) { return object, nil } // set the field value - return object, fs.set(object, s, f) + return object, fs.set(object, s, f, partial) default: return object, nil } } // findPartialSetter finds the setter matching the name if one exists -func (fs *partialFieldSetter) findPartialSetter(field *yaml.RNode) ( - *fieldmeta.PartialFieldSetter, *fieldmeta.FieldMeta, error) { +func (fs *fieldSetter) findSetter(field *yaml.RNode) ( + *fieldmeta.PartialFieldSetter, *fieldmeta.FieldMeta, bool, error) { // check if there are any substitutions for this field var fm = &fieldmeta.FieldMeta{} if err := fm.Read(field); err != nil { - return nil, nil, err + return nil, nil, false, err } if fs.SetBy != "" { fm.Extensions.SetBy = fs.SetBy @@ -79,18 +79,23 @@ func (fs *partialFieldSetter) findPartialSetter(field *yaml.RNode) ( fm.Schema.Description = fs.Description } + if fm.Extensions.FieldSetter != nil && fm.Extensions.FieldSetter.Name == fs.Name { + return fm.Extensions.FieldSetter, fm, false, nil + } + // check if there is a matching substitution for i := range fm.Extensions.PartialFieldSetters { if fm.Extensions.PartialFieldSetters[i].Name == fs.Name { - return &fm.Extensions.PartialFieldSetters[i], fm, nil + return &fm.Extensions.PartialFieldSetters[i], fm, true, nil } } - return nil, nil, nil + return nil, nil, false, nil } // set performs the substitution for the given field, substitution, and metadata -func (fs *partialFieldSetter) set( - field *yaml.RNode, s *fieldmeta.PartialFieldSetter, f *fieldmeta.FieldMeta) error { +func (fs *fieldSetter) set( + field *yaml.RNode, s *fieldmeta.PartialFieldSetter, + f *fieldmeta.FieldMeta, partial bool) error { if s.Value == fs.Value || !strings.Contains(field.YNode().Value, s.Value) { // no substitutions necessary -- already substituted or doesn't have the set value // which acts as a marker @@ -100,8 +105,13 @@ func (fs *partialFieldSetter) set( // record that the config has been modified fs.Count++ - // replace the current value with the new value - field.YNode().Value = strings.ReplaceAll(field.YNode().Value, s.Value, fs.Value) + if !partial { + // full setter + field.YNode().Value = fs.Value + } else { + // replace the current value with the new value + field.YNode().Value = strings.ReplaceAll(field.YNode().Value, s.Value, fs.Value) + } // be sure to set the tag to the matching type so the yaml doesn't incorrectly quote //integers or booleans as strings diff --git a/kyaml/setters/lookupyaml.go b/kyaml/setters/lookupyaml.go index 425b58a62..ecc5923ce 100644 --- a/kyaml/setters/lookupyaml.go +++ b/kyaml/setters/lookupyaml.go @@ -54,6 +54,22 @@ func (ls *lookupSetters) lookup(field *yaml.RNode) error { return err } + if fm.Extensions.FieldSetter != nil { + if ls.Name != "" && ls.Name != fm.Extensions.FieldSetter.Name { + // skip this setter, it doesn't match the specified setter + return nil + } + // full setter + ls.Setters = append(ls.Setters, setter{ + PartialFieldSetter: *fm.Extensions.FieldSetter, + Description: fm.Schema.Description, + Type: fm.Schema.Type[0], + SetBy: fm.Extensions.SetBy, + }) + return nil + } + + // partial setters for i := range fm.Extensions.PartialFieldSetters { if ls.Name != "" && ls.Name != fm.Extensions.PartialFieldSetters[i].Name { // skip this setter