mirror of
https://github.com/hanzoai/deploy.git
synced 2026-10-07 08:44:50 +00:00
Signed-off-by: Kentaro Abe <[email protected]> Signed-off-by: Kentaro Abe <[email protected]> Co-authored-by: Michael Crenshaw <[email protected]>
170 lines
5.3 KiB
Go
170 lines
5.3 KiB
Go
package v1alpha1
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"sigs.k8s.io/yaml"
|
|
)
|
|
|
|
// Set the ValuesObject property to the json representation of the yaml contained in value
|
|
// Remove Values property if present
|
|
func (h *ApplicationSourceHelm) SetValuesString(value string) error {
|
|
if value == "" {
|
|
h.ValuesObject = nil
|
|
h.Values = ""
|
|
} else {
|
|
data, err := yaml.YAMLToJSON([]byte(value))
|
|
if err != nil {
|
|
return fmt.Errorf("failed converting yaml to json: %w", err)
|
|
}
|
|
var v any
|
|
if err := json.Unmarshal(data, &v); err != nil {
|
|
return fmt.Errorf("failed to unmarshal json: %w", err)
|
|
}
|
|
switch v.(type) {
|
|
case string:
|
|
case map[string]any:
|
|
default:
|
|
return fmt.Errorf("invalid type %q", reflect.TypeOf(v))
|
|
}
|
|
h.ValuesObject = &runtime.RawExtension{Raw: data}
|
|
h.Values = ""
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Equals reports whether h and other are semantically equal. ValuesObject is compared by
|
|
// marshaling both sides to canonical JSON so that HTML-escaping differences (e.g. '&' vs
|
|
// '&') that arise between the Kubernetes API server and encoding/json do not cause
|
|
// a spurious inequality.
|
|
func (h *ApplicationSourceHelm) Equals(other *ApplicationSourceHelm) bool {
|
|
if h == nil && other == nil {
|
|
return true
|
|
}
|
|
if h == nil || other == nil {
|
|
return false
|
|
}
|
|
// Compare ValuesObject: skip the JSON normalisation round-trip when raw bytes are
|
|
// already identical. Otherwise normalise both to canonical JSON to absorb
|
|
// HTML-escaping differences (e.g. '&' vs '&').
|
|
var hRaw, otherRaw []byte
|
|
if h.ValuesObject != nil {
|
|
hRaw = h.ValuesObject.Raw
|
|
}
|
|
if other.ValuesObject != nil {
|
|
otherRaw = other.ValuesObject.Raw
|
|
}
|
|
if !bytes.Equal(hRaw, otherRaw) &&
|
|
!bytes.Equal(canonicalValuesJSON(h.ValuesObject), canonicalValuesJSON(other.ValuesObject)) {
|
|
return false
|
|
}
|
|
hCopy, otherCopy := h.DeepCopy(), other.DeepCopy()
|
|
hCopy.ValuesObject = nil
|
|
otherCopy.ValuesObject = nil
|
|
return reflect.DeepEqual(hCopy, otherCopy)
|
|
}
|
|
|
|
// canonicalValuesJSON returns the canonical JSON encoding of a ValuesObject by round-tripping
|
|
// through json.Unmarshal + json.Marshal. Returns the original Raw bytes for invalid JSON,
|
|
// or nil if the extension is absent.
|
|
func canonicalValuesJSON(ext *runtime.RawExtension) []byte {
|
|
if ext == nil || ext.Raw == nil {
|
|
return nil
|
|
}
|
|
var v any
|
|
if err := json.Unmarshal(ext.Raw, &v); err != nil {
|
|
return ext.Raw
|
|
}
|
|
b, err := json.Marshal(v)
|
|
if err != nil {
|
|
return ext.Raw
|
|
}
|
|
return b
|
|
}
|
|
|
|
func (h *ApplicationSourceHelm) ValuesYAML() []byte {
|
|
if h.ValuesObject == nil || h.ValuesObject.Raw == nil {
|
|
return []byte(h.Values)
|
|
}
|
|
b, err := yaml.JSONToYAML(h.ValuesObject.Raw)
|
|
if err != nil {
|
|
// This should be impossible, because rawValue isn't set directly.
|
|
return []byte{}
|
|
}
|
|
return b
|
|
}
|
|
|
|
func (h *ApplicationSourceHelm) ValuesIsEmpty() bool {
|
|
return len(h.ValuesYAML()) == 0
|
|
}
|
|
|
|
// String returns a human-readable representation of ApplicationSourceHelm.
|
|
// It replaces the suppressed auto-generated stringer so that
|
|
// ValuesObject is rendered as YAML rather than as a raw byte-array
|
|
// See https://github.com/argoproj/argo-cd/issues/18342
|
|
//
|
|
// The format mirrors what gogo-proto produces for every other field, so the
|
|
// only observable difference is the ValuesObject rendering. If new fields are
|
|
// added to ApplicationSourceHelm, they must be added here as well.
|
|
func (h *ApplicationSourceHelm) String() string {
|
|
if h == nil {
|
|
return "nil"
|
|
}
|
|
|
|
var parametersBuilder strings.Builder
|
|
parametersBuilder.WriteString("[]HelmParameter{")
|
|
for _, f := range h.Parameters {
|
|
parametersBuilder.WriteString(strings.Replace(f.String(), `&`, ``, 1))
|
|
parametersBuilder.WriteString(",")
|
|
}
|
|
parametersBuilder.WriteString("}")
|
|
|
|
var fileParametersBuilder strings.Builder
|
|
fileParametersBuilder.WriteString("[]HelmFileParameter{")
|
|
for _, f := range h.FileParameters {
|
|
fileParametersBuilder.WriteString(strings.Replace(f.String(), `&`, ``, 1))
|
|
fileParametersBuilder.WriteString(",")
|
|
}
|
|
fileParametersBuilder.WriteString("}")
|
|
|
|
valuesObjectStr := "nil"
|
|
if h.ValuesObject != nil {
|
|
// Render the JSON-encoded RawExtension as YAML instead of the
|
|
// default %v formatting of []byte (which produces "[123 34 ...]").
|
|
valuesObjectStr = "&runtime.RawExtension{" + h.ValuesString() + "}"
|
|
}
|
|
|
|
return strings.Join([]string{
|
|
`&ApplicationSourceHelm{`,
|
|
`ValueFiles:` + fmt.Sprintf("%v", h.ValueFiles) + `,`,
|
|
`Parameters:` + parametersBuilder.String() + `,`,
|
|
`ReleaseName:` + h.ReleaseName + `,`,
|
|
`Values:` + h.Values + `,`,
|
|
`FileParameters:` + fileParametersBuilder.String() + `,`,
|
|
`Version:` + h.Version + `,`,
|
|
`PassCredentials:` + strconv.FormatBool(h.PassCredentials) + `,`,
|
|
`IgnoreMissingValueFiles:` + strconv.FormatBool(h.IgnoreMissingValueFiles) + `,`,
|
|
`SkipCrds:` + strconv.FormatBool(h.SkipCrds) + `,`,
|
|
`ValuesObject:` + valuesObjectStr + `,`,
|
|
`Namespace:` + h.Namespace + `,`,
|
|
`KubeVersion:` + h.KubeVersion + `,`,
|
|
`APIVersions:` + fmt.Sprintf("%v", h.APIVersions) + `,`,
|
|
`SkipTests:` + strconv.FormatBool(h.SkipTests) + `,`,
|
|
`SkipSchemaValidation:` + strconv.FormatBool(h.SkipSchemaValidation) + `,`,
|
|
`}`,
|
|
}, "")
|
|
}
|
|
|
|
func (h *ApplicationSourceHelm) ValuesString() string {
|
|
if h.ValuesObject == nil || h.ValuesObject.Raw == nil {
|
|
return h.Values
|
|
}
|
|
return strings.TrimSuffix(string(h.ValuesYAML()), "\n")
|
|
}
|