Repository: helm/helm
File: pkg/action/hooks.go (Go)

Code before:
		case "Job":
			return cfg.outputContainerLogsForListOptions(namespace, metav1.ListOptions{LabelSelector: fmt.Sprintf("job-name=%s", h.Name)})
		case "Pod":
			return cfg.outputContainerLogsForListOptions(namespace, metav1.ListOptions{FieldSelector: fmt.Sprintf("metadata.name=%s", h.Name)})
		default:
			return nil
		}
	}
	return nil
}

func (cfg *Configuration) outputContainerLogsForListOptions(namespace string, listOptions metav1.ListOptions) error {
	// TODO Helm 4: Remove this check when GetPodList and OutputContainerLogsForPodList are moved from InterfaceLogs to Interface
	if kubeClient, ok := cfg.KubeClient.(kube.InterfaceLogs); ok {
		podList, err := kubeClient.GetPodList(namespace, listOptions)
		if err != nil {
			return err
		}
		err = kubeClient.OutputContainerLogsForPodList(podList, namespace, log.Writer())
		return err
	}
	return nil
}

func (cfg *Configuration) deriveNamespace(h *release.Hook, namespace string) (string, error) {
	values, err := chartutil.ReadValues([]byte(h.Manifest))
	if err != nil {
		return "", errors.Wrapf(err, "unable to parse kubernetes manifest for output logs hook %s", h.Path)
	}
	value, err := values.PathValue("metadata.namespace")
	switch err.(type) {
	case nil:
		return value.(string), nil
	case chartutil.ErrNoValue:
		return namespace, nil
	default:
		return "", errors.Wrapf(err, "unable to parse path of metadata.namespace in yaml for output logs hook %s", h.Path)
	}
}

// hookHasOutputLogPolicy determines whether the defined hook output log policy matches the hook output log policies
// supported by helm.
func hookHasOutputLogPolicy(h *release.Hook, policy release.HookOutputLogPolicy) bool {
	for _, v := range h.OutputLogPolicies {
		if policy == v {
			return true
		}
	}
	return false
}


Review comment (suggestion):
I don't think chart's Values type should be used to process generic yaml...

A generic parser should be used instead. e.g. https://pkg.go.dev/k8s.io/apimachinery/pkg/runtime/serializer#CodecFactory.UniversalDeserializer

Code after:
	case "Job":
		return cfg.outputContainerLogsForListOptions(namespace, metav1.ListOptions{LabelSelector: fmt.Sprintf("job-name=%s", h.Name)})
	case "Pod":
		return cfg.outputContainerLogsForListOptions(namespace, metav1.ListOptions{FieldSelector: fmt.Sprintf("metadata.name=%s", h.Name)})
	default:
		return nil
	}
}

func (cfg *Configuration) outputContainerLogsForListOptions(namespace string, listOptions metav1.ListOptions) error {
	// TODO Helm 4: Remove this check when GetPodList and OutputContainerLogsForPodList are moved from InterfaceLogs to Interface
	if kubeClient, ok := cfg.KubeClient.(kube.InterfaceLogs); ok {
		podList, err := kubeClient.GetPodList(namespace, listOptions)
		if err != nil {
			return err
		}
		err = kubeClient.OutputContainerLogsForPodList(podList, namespace, cfg.HookOutputFunc)
		return err
	}
	return nil
}

func (cfg *Configuration) deriveNamespace(h *release.Hook, namespace string) (string, error) {
	tmp := struct {
		Metadata struct {
			Namespace string
		}
	}{}
	err := yaml.Unmarshal([]byte(h.Manifest), &tmp)
	if err != nil {
		return "", errors.Wrapf(err, "unable to parse metadata.namespace from kubernetes manifest for output logs hook %s", h.Path)
	}
	if tmp.Metadata.Namespace == "" {
		return namespace, nil
	}
	return tmp.Metadata.Namespace, nil
}

// hookHasOutputLogPolicy determines whether the defined hook output log policy matches the hook output log policies
// supported by helm.
func hookHasOutputLogPolicy(h *release.Hook, policy release.HookOutputLogPolicy) bool {
	return slices.Contains(h.OutputLogPolicies, policy)
}