use super::common::{fail, hl, ok, repo_root, staged_files, warn, which};
use crate::check::Outcome;
use std::path::Path;
use std::process::{Command, Stdio};
pub const JSON: &[&str] = &[".json"];
pub const YAML: &[&str] = &[".yaml", ".yml"];
pub const EXTS: &[&str] = &[".json", ".yaml", ".yml"];
pub fn is_helm_template(root: &str, file: &str) -> bool {
let Some(i) = file.find("/templates/") else {
return false;
};
Path::new(root)
.join(&file[..i])
.join("Chart.yaml")
.is_file()
}
fn parses(root: &str, tool: &str, args: &[&str]) -> bool {
Command::new(super::common::program(tool))
.args(args)
.current_dir(root)
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false)
}
pub fn run(_args: &[std::ffi::OsString]) -> Outcome {
let json: Vec<String> = staged_files(JSON);
let yaml: Vec<String> = staged_files(YAML);
if json.is_empty() && yaml.is_empty() {
return Outcome::Passed;
}
let root = repo_root();
let mut failed = false;
let mut unavailable = false;
if !json.is_empty() {
if which("node").is_some() {
for f in &json {
let script = r#"JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"))"#;
if !parses(&root, "node", &["-e", script, "--", f]) {
fail(&format!("Invalid JSON: {}", hl(f)));
failed = true;
}
}
} else {
warn(&format!(
"JSON files detected. To lint them, install {}",
hl("node")
));
unavailable = true;
}
}
if !yaml.is_empty() {
if which("yq").is_some() {
for f in &yaml {
if is_helm_template(&root, f) {
continue;
}
if !parses(&root, "yq", &["e", "true", "--", f]) {
fail(&format!("Invalid YAML: {}", hl(f)));
failed = true;
}
}
} else {
warn(&format!(
"YAML files detected. To lint them, install {}",
hl("yq")
));
unavailable = true;
}
}
match (failed, unavailable) {
(true, _) => Outcome::Failed,
(false, true) => Outcome::Unavailable,
(false, false) => {
ok("Json/Yaml Lint passed");
Outcome::Passed
}
}
}