pull/32204/merge
Jeff Rescignano 1 day ago committed by GitHub
commit fb1300af3c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -34,6 +34,7 @@ import (
"text/template"
"time"
"go.yaml.in/yaml/v3"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/discovery"
@ -204,6 +205,13 @@ func annotateAndMerge(files map[string]string) (string, error) {
if strings.TrimSpace(doc) == "" {
continue
}
// kio.ParseAll flattens `kind: List` into one document per item; resolve aliases
// first so an anchor and its alias aren't split across documents (anchors are
// document-scoped), which would leave the alias dangling.
doc, err := resolveYAMLAliases(doc)
if err != nil {
return "", fmt.Errorf("resolving aliases in %s: %w", fname, err)
}
manifests, err := kio.ParseAll(doc)
if err != nil {
return "", fmt.Errorf("parsing %s: %w", fname, err)
@ -224,6 +232,68 @@ func annotateAndMerge(files map[string]string) (string, error) {
return merged, nil
}
// resolveYAMLAliases materializes YAML aliases within a single document, leaving
// documents that contain none unchanged.
func resolveYAMLAliases(doc string) (string, error) {
var node yaml.Node
if err := yaml.Unmarshal([]byte(doc), &node); err != nil {
// Preserve the surrounding code's leniency for badly-formed docs;
// kio.ParseAll reports them downstream.
return doc, nil
}
if !resolveAliasNodes(&node) {
return doc, nil
}
stripAnchors(&node)
var buf bytes.Buffer
enc := yaml.NewEncoder(&buf)
enc.SetIndent(2)
if err := enc.Encode(&node); err != nil {
return "", err
}
if err := enc.Close(); err != nil {
return "", err
}
return buf.String(), nil
}
// resolveAliasNodes replaces alias nodes with a deep copy of their anchor target,
// returning true if any replacement was made.
func resolveAliasNodes(n *yaml.Node) bool {
changed := false
for i, c := range n.Content {
if c.Kind == yaml.AliasNode && c.Alias != nil {
n.Content[i] = deepCopyClearAnchor(c.Alias)
changed = true
continue
}
if resolveAliasNodes(c) {
changed = true
}
}
return changed
}
// deepCopyClearAnchor returns a deep copy of n with anchors removed.
func deepCopyClearAnchor(n *yaml.Node) *yaml.Node {
cp := *n
cp.Anchor = ""
cp.Alias = nil
cp.Content = make([]*yaml.Node, len(n.Content))
for i, c := range n.Content {
cp.Content[i] = deepCopyClearAnchor(c)
}
return &cp
}
// stripAnchors clears any remaining anchor names in the tree.
func stripAnchors(n *yaml.Node) {
n.Anchor = ""
for _, c := range n.Content {
stripAnchors(c)
}
}
// splitAndDeannotate reconstructs individual files from a merged YAML stream,
// removing filename annotations and grouping documents by their original filenames.
// Documents without a filename annotation are assigned a synthesized name of the

@ -508,6 +508,70 @@ metadata:
postrenderer.helm.sh/postrender-filename: 'templates/multi.yaml'
data:
key: value2
`,
},
{
name: "kind List with anchor shared across items",
files: map[string]string{
"templates/list.yaml": `
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ConfigMap
metadata:
name: cm-a
data: &shared
key: value
- apiVersion: v1
kind: ConfigMap
metadata:
name: cm-b
data: *shared`,
},
expected: `apiVersion: v1
kind: ConfigMap
metadata:
name: cm-a
annotations:
postrenderer.helm.sh/postrender-filename: 'templates/list.yaml'
data:
key: value
---
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-b
annotations:
postrenderer.helm.sh/postrender-filename: 'templates/list.yaml'
data:
key: value
`,
},
{
name: "anchor and alias within a single manifest",
files: map[string]string{
"templates/cm.yaml": `
apiVersion: v1
kind: ConfigMap
metadata:
name: cm
data:
defaults: &d
a: "1"
prod: *d`,
},
expected: `apiVersion: v1
kind: ConfigMap
metadata:
name: cm
annotations:
postrenderer.helm.sh/postrender-filename: 'templates/cm.yaml'
data:
defaults:
a: "1"
prod:
a: "1"
`,
},
{

Loading…
Cancel
Save