Skip to main content

helm_schema_k8s/diagnostic/
format_text.rs

1use std::fmt::Write;
2
3use super::diagnostic::Diagnostic;
4
5/// Render a [`Diagnostic`] as a human-readable line. Returns
6/// `"warning: …"` for diagnostics representing problems, `"info: …"`
7/// for diagnostics describing successful but noteworthy outcomes.
8#[must_use]
9#[expect(
10    clippy::too_many_lines,
11    reason = "one exhaustive match keeps every diagnostic's user-facing rendering auditable"
12)]
13pub fn format_diagnostic_text(diagnostic: &Diagnostic) -> String {
14    match diagnostic {
15        Diagnostic::MissingSchema {
16            kind,
17            api_version,
18            k8s_versions_tried,
19            available_in_cache_versions,
20            suggested_k8s_version,
21            hint,
22            ..
23        } => {
24            let mut out = String::new();
25            let _ = if api_version.trim().is_empty() {
26                write!(
27                    out,
28                    "warning: no upstream Kubernetes JSON schema found for {kind} (apiVersion unknown)"
29                )
30            } else {
31                write!(
32                    out,
33                    "warning: no upstream Kubernetes JSON schema found for {kind} ({api_version})"
34                )
35            };
36            if !k8s_versions_tried.is_empty() {
37                let _ = write!(out, " in {}", k8s_versions_tried.join(", "));
38            }
39            if !available_in_cache_versions.is_empty() {
40                let _ = write!(
41                    out,
42                    "; available in local cache for: {}",
43                    available_in_cache_versions.join(", ")
44                );
45            }
46            if let Some(s) = suggested_k8s_version {
47                let _ = write!(out, "; try --k8s-version {s}");
48            }
49            if let Some(h) = hint {
50                let _ = write!(out, "; {h}");
51            }
52            out
53        }
54        Diagnostic::ResolvedFromFallbackVersion {
55            kind,
56            api_version,
57            primary_version,
58            resolved_version,
59        } => format!(
60            "info: {kind} ({api_version}) resolved from K8s {resolved_version} (not in primary {primary_version})"
61        ),
62        Diagnostic::InferredApiVersion {
63            kind,
64            inferred_api_version,
65            source,
66            ..
67        } => format!(
68            "info: inferred apiVersion {inferred_api_version} for {kind} (source: {source:?})"
69        ),
70        Diagnostic::AmbiguousApiVersion { kind, candidates } => {
71            let list = candidates
72                .iter()
73                .map(|c| c.api_version.as_str())
74                .collect::<Vec<_>>()
75                .join(", ");
76            format!("warning: ambiguous apiVersion inference for {kind}: candidates [{list}]")
77        }
78        Diagnostic::CrdVersionNotFound {
79            group,
80            kind,
81            requested_version,
82            locations_tried,
83        } => {
84            let mut out = format!(
85                "warning: CRD schema not found for {group}/{kind} version {requested_version}"
86            );
87            if !locations_tried.is_empty() {
88                let _ = write!(out, "; tried: {}", locations_tried.join(", "));
89            }
90            out
91        }
92        Diagnostic::CrdVersionAvailableAtOtherVersions {
93            group,
94            kind,
95            requested_version,
96            available_versions,
97        } => format!(
98            "info: {group}/{kind} {requested_version} not found, but cached at versions: {}",
99            available_versions.join(", ")
100        ),
101        Diagnostic::LocalOverrideUnreadable {
102            kind,
103            api_version,
104            override_path,
105            io_error,
106        } => format!(
107            "warning: local override for {kind} ({api_version}) at {override_path} is unreadable: {io_error}"
108        ),
109        Diagnostic::CacheLayoutInvalidated {
110            cache_root,
111            previous_marker,
112            current_marker,
113        } => {
114            let prev = previous_marker
115                .map(|n| n.to_string())
116                .unwrap_or_else(|| "none".to_string());
117            format!(
118                "info: cache layout for {cache_root} invalidated (previous: {prev}, current: {current_marker})"
119            )
120        }
121        Diagnostic::CacheLayoutForwardIncompatible {
122            cache_root,
123            on_disk_marker,
124            compiled_marker,
125        } => format!(
126            "warning: cache at {cache_root} was written by a newer helm-schema (on-disk: {on_disk_marker}, this binary: {compiled_marker}); refusing to mutate"
127        ),
128        Diagnostic::InputChannelNumericRangeAmbiguity { value_path } => format!(
129            "warning: {value_path} has input-channel-dependent integer range semantics: Helm can iterate an integer from --set but rejects the same JSON number from a values file or --set-json; JSON Schema cannot distinguish those inputs"
130        ),
131    }
132}