SplitYAMLDocuments splits a potentially multi-document YAML file into individual documents, extracting kind and name from each.
(rawData []byte)
| 163 | // SplitYAMLDocuments splits a potentially multi-document YAML file into individual documents, |
| 164 | // extracting kind and name from each. |
| 165 | func SplitYAMLDocuments(rawData []byte) ([]*YAMLDoc, error) { |
| 166 | decoder := yaml.NewDecoder(bytes.NewReader(rawData)) |
| 167 | |
| 168 | var docs []*YAMLDoc |
| 169 | for { |
| 170 | var node yaml.Node |
| 171 | if err := decoder.Decode(&node); err != nil { |
| 172 | if errors.Is(err, io.EOF) { |
| 173 | break |
| 174 | } |
| 175 | return nil, fmt.Errorf("decoding YAML document: %w", err) |
| 176 | } |
| 177 | |
| 178 | // Marshal node back to bytes for the per-resource apply |
| 179 | docBytes, err := yaml.Marshal(&node) |
| 180 | if err != nil { |
| 181 | return nil, fmt.Errorf("marshalling YAML node: %w", err) |
| 182 | } |
| 183 | |
| 184 | // Extract kind and name via partial unmarshal |
| 185 | var header struct { |
| 186 | Kind string `yaml:"kind"` |
| 187 | Metadata struct { |
| 188 | Name string `yaml:"name"` |
| 189 | } `yaml:"metadata"` |
| 190 | } |
| 191 | if err := yaml.Unmarshal(docBytes, &header); err != nil { |
| 192 | return nil, fmt.Errorf("extracting document kind: %w", err) |
| 193 | } |
| 194 | |
| 195 | if header.Kind == "" { |
| 196 | return nil, fmt.Errorf("missing 'kind' field in YAML document") |
| 197 | } |
| 198 | |
| 199 | if header.Metadata.Name == "" { |
| 200 | return nil, fmt.Errorf("missing 'metadata.name' field in YAML document of kind %q", header.Kind) |
| 201 | } |
| 202 | |
| 203 | docs = append(docs, &YAMLDoc{ |
| 204 | Kind: header.Kind, |
| 205 | Name: header.Metadata.Name, |
| 206 | RawData: docBytes, |
| 207 | }) |
| 208 | } |
| 209 | |
| 210 | return docs, nil |
| 211 | } |