helm-schema-k8s 0.0.7

Generate an accurate JSON schema for any helm chart
Documentation
use helm_schema_core::{CapabilityOracle, ResourceRef};

use crate::diagnostic::Diagnostic;
use crate::filename::candidate_filenames_for_resource;

use super::resource_lookup_plan::missing_schema_attribution_candidates;
use super::trait_def::K8sSchemaProvider;

/// Projects user-facing diagnostics from a failed knowledge lookup trace.
pub(crate) struct MissingLookupDiagnostics<'a> {
    providers: &'a [Box<dyn K8sSchemaProvider>],
    capability_oracle: &'a dyn CapabilityOracle,
}

impl<'a> MissingLookupDiagnostics<'a> {
    pub(crate) fn new(
        providers: &'a [Box<dyn K8sSchemaProvider>],
        capability_oracle: &'a dyn CapabilityOracle,
    ) -> Self {
        Self {
            providers,
            capability_oracle,
        }
    }

    pub(crate) fn project(
        &self,
        resource: &ResourceRef,
        local_override_unreadable: Option<Diagnostic>,
    ) -> Vec<Diagnostic> {
        if let Some(diagnostic) = local_override_unreadable {
            return vec![diagnostic];
        }
        let mut diagnostics = Vec::new();
        for attribution in missing_schema_attribution_candidates(resource, self.capability_oracle) {
            diagnostics.push(self.missing_schema_diagnostic(&attribution));
            for provider in self.providers {
                diagnostics.extend(provider.missing_schema_provider_diagnostics(&attribution));
            }
        }
        diagnostics
    }

    fn missing_schema_diagnostic(&self, resource: &ResourceRef) -> Diagnostic {
        let available_in_cache_versions = self.collect_available_cache_versions(resource);
        Diagnostic::MissingSchema {
            kind: resource.kind.clone(),
            api_version: resource.api_version.clone(),
            k8s_versions_tried: self.collect_tried_k8s_versions(),
            tried_filenames: candidate_filenames_for_resource(resource),
            suggested_k8s_version: available_in_cache_versions.first().cloned(),
            available_in_cache_versions,
            hint: missing_schema_hint(resource),
        }
    }

    fn collect_available_cache_versions(&self, resource: &ResourceRef) -> Vec<String> {
        let mut out: Vec<String> = self
            .providers
            .iter()
            .flat_map(|provider| provider.cache_versions_holding(resource))
            .collect();
        out.sort();
        out.dedup();
        out
    }

    fn collect_tried_k8s_versions(&self) -> Vec<String> {
        self.providers
            .iter()
            .filter_map(|provider| provider.k8s_version_chain())
            .flatten()
            .collect()
    }
}

/// Returns a short user-facing hint for resources we know were removed
/// from a specific K8s minor — e.g. HPA `autoscaling/v2beta1` going
/// away in v1.25.
fn missing_schema_hint(resource: &ResourceRef) -> Option<String> {
    if resource.kind == "HorizontalPodAutoscaler" && resource.api_version == "autoscaling/v2beta1" {
        return Some(
            "autoscaling/v2beta1 HorizontalPodAutoscaler was removed in Kubernetes v1.25+"
                .to_string(),
        );
    }
    None
}

#[cfg(test)]
#[path = "tests/miss_diagnostics.rs"]
mod tests;