@@ -42,6 +42,7 @@ type WalkTemplatesOptions struct {
4242 failForUnknownTypes bool
4343 patchFormat runtimehooksv1.PatchType
4444 // TODO: add the possibility to set patchFormat for single patches only, eg. via a func(requestItem) format.
45+ KeepEmptyFields bool
4546}
4647
4748// newWalkTemplatesOptions returns a WalkTemplatesOptions with default values.
@@ -61,6 +62,14 @@ func (f FailForUnknownTypes) ApplyToWalkTemplates(in *WalkTemplatesOptions) {
6162 in .failForUnknownTypes = true
6263}
6364
65+ // KeepEmptyFields defines if WalkTemplates should keep empty fields which is old behavior
66+ type KeepEmptyFields struct {}
67+
68+ // ApplyToWalkTemplates applies this configuration to the given WalkTemplatesOptions.
69+ func (f KeepEmptyFields ) ApplyToWalkTemplates (in * WalkTemplatesOptions ) {
70+ in .KeepEmptyFields = true
71+ }
72+
6473// PatchFormat defines the patch format that WalkTemplates should generate.
6574// If not set, JSONPatchType will be used.
6675type PatchFormat struct {
@@ -147,14 +156,22 @@ func WalkTemplates(ctx context.Context, decoder runtime.Decoder, req *runtimehoo
147156 var patch []byte
148157 switch options .patchFormat {
149158 case runtimehooksv1 .JSONPatchType :
150- patch , err = createJSONPatch (requestItem .Object .Raw , modified )
159+ if options .KeepEmptyFields {
160+ patch , err = createJSONPatchKeepEmptyFields (original , modified )
161+ } else {
162+ patch , err = createJSONPatch (requestItem .Object .Raw , modified )
163+ }
151164 if err != nil {
152165 resp .Status = runtimehooksv1 .ResponseStatusFailure
153166 resp .Message = err .Error ()
154167 return
155168 }
156169 case runtimehooksv1 .JSONMergePatchType :
157- patch , err = createJSONMergePatch (requestItem .Object .Raw , modified )
170+ if options .KeepEmptyFields {
171+ patch , err = createJSONMergePatchKeepEmptyFields (original , modified )
172+ } else {
173+ patch , err = createJSONMergePatch (requestItem .Object .Raw , modified )
174+ }
158175 if err != nil {
159176 resp .Status = runtimehooksv1 .ResponseStatusFailure
160177 resp .Message = err .Error ()
@@ -207,3 +224,48 @@ func createJSONMergePatch(marshalledOriginal []byte, modified runtime.Object) ([
207224
208225 return patch , nil
209226}
227+
228+ // createJSONPatchKeepEmptyFields creates a RFC 6902 JSON patch from the original and the modified object.
229+ func createJSONPatchKeepEmptyFields (original , modified runtime.Object ) ([]byte , error ) {
230+ marshalledOriginal , err := json .Marshal (original )
231+ if err != nil {
232+ return nil , errors .Errorf ("failed to marshal original object: %v" , err )
233+ }
234+
235+ marshalledModified , err := json .Marshal (modified )
236+ if err != nil {
237+ return nil , errors .Errorf ("failed to marshal modified object: %v" , err )
238+ }
239+
240+ patch , err := jsonpatch .CreatePatch (marshalledOriginal , marshalledModified )
241+ if err != nil {
242+ return nil , errors .Errorf ("failed to create patch: %v" , err )
243+ }
244+
245+ patchBytes , err := json .Marshal (patch )
246+ if err != nil {
247+ return nil , errors .Errorf ("failed to marshal patch: %v" , err )
248+ }
249+
250+ return patchBytes , nil
251+ }
252+
253+ // createJSONMergePatchKeepEmptyFields creates a RFC 7396 JSON merge patch from the original and the modified object.
254+ func createJSONMergePatchKeepEmptyFields (original , modified runtime.Object ) ([]byte , error ) {
255+ marshalledOriginal , err := json .Marshal (original )
256+ if err != nil {
257+ return nil , errors .Errorf ("failed to marshal original object: %v" , err )
258+ }
259+
260+ marshalledModified , err := json .Marshal (modified )
261+ if err != nil {
262+ return nil , errors .Errorf ("failed to marshal modified object: %v" , err )
263+ }
264+
265+ patch , err := mergepatch .CreateMergePatch (marshalledOriginal , marshalledModified )
266+ if err != nil {
267+ return nil , errors .Errorf ("failed to create patch: %v" , err )
268+ }
269+
270+ return patch , nil
271+ }
0 commit comments