func PatchYAML()

in internal/packages/changelog/yaml.go [20:100]


func PatchYAML(d []byte, patch Revision) ([]byte, error) {
	var nodes []yaml.Node
	err := yaml.Unmarshal(d, &nodes)
	if err != nil {
		return nil, err
	}

	patchVersion, err := semver.NewVersion(patch.Version)
	if err != nil {
		return nil, err
	}

	patched := false
	var result []yaml.Node
	for _, node := range nodes {
		if patched {
			result = append(result, node)
			continue
		}

		var entry Revision
		err := node.Decode(&entry)
		if err != nil {
			result = append(result, node)
			continue
		}

		foundVersion, err := semver.NewVersion(entry.Version)
		if err != nil {
			return nil, err
		}

		if foundVersion.GreaterThan(patchVersion) {
			return nil, errors.New("cannot add change to old version")
		}

		var newNode yaml.Node
		if patchVersion.Equal(foundVersion) {
			// Add the change to current entry.
			entry.Changes = append(patch.Changes, entry.Changes...)
			err := newNode.Encode(entry)
			if err != nil {
				return nil, err
			}
			// Keep comments of the original node.
			newNode.HeadComment = node.HeadComment
			newNode.LineComment = node.LineComment
			newNode.FootComment = node.FootComment
			// Quote version to keep common style.
			setYamlMapValueStyle(&newNode, "version", yaml.DoubleQuotedStyle)
			result = append(result, newNode)
			patched = true
			continue
		}

		// Add the change before first entry
		err = newNode.Encode(patch)
		if err != nil {
			return nil, err
		}
		// If there is a comment on top, leave it there.
		if node.HeadComment != "" {
			newNode.HeadComment = node.HeadComment
			node.HeadComment = ""
		}
		// Quote version to keep common style.
		setYamlMapValueStyle(&newNode, "version", yaml.DoubleQuotedStyle)
		result = append(result, newNode, node)
		patched = true
	}

	if !patched {
		return nil, errors.New("changelog entry was not added, this is probably a bug")
	}

	d, err = formatResult(result)
	if err != nil {
		return nil, fmt.Errorf("failed to format manifest: %w", err)
	}
	return d, nil
}