amont_runtime/hooks/
lint_json_yaml.rs1use super::common::{fail, hl, ok, repo_root, staged_files, warn, which};
5use crate::check::Outcome;
6use std::path::Path;
7use std::process::{Command, Stdio};
8
9pub const JSON: &[&str] = &[".json"];
19pub const YAML: &[&str] = &[".yaml", ".yml"];
20pub const EXTS: &[&str] = &[".json", ".yaml", ".yml"];
21
22pub fn is_helm_template(root: &str, file: &str) -> bool {
27 let Some(i) = file.find("/templates/") else {
28 return false;
29 };
30 Path::new(root)
31 .join(&file[..i])
32 .join("Chart.yaml")
33 .is_file()
34}
35
36fn parses(root: &str, tool: &str, args: &[&str]) -> bool {
37 let mut cmd = Command::new(super::common::program(tool));
38 cmd.args(args)
39 .current_dir(root)
40 .stdin(Stdio::null())
41 .stdout(Stdio::null())
42 .stderr(Stdio::null());
43 super::common::bounded_success(&mut cmd, tool)
44}
45
46pub fn run(_args: &[std::ffi::OsString]) -> Outcome {
47 let json: Vec<String> = staged_files(JSON);
48 let yaml: Vec<String> = staged_files(YAML);
49 if json.is_empty() && yaml.is_empty() {
50 return Outcome::Passed;
51 }
52 let root = repo_root();
53 let mut failed = false;
57 let mut unavailable = false;
58
59 if !json.is_empty() {
60 if which("node").is_some() {
61 for f in &json {
62 let script = r#"JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"))"#;
63 if !parses(&root, "node", &["-e", script, "--", f]) {
66 fail(&format!("Invalid JSON: {}", hl(f)));
67 failed = true;
68 }
69 }
70 } else {
71 warn(&format!(
72 "JSON files detected. To lint them, install {}",
73 hl("node")
74 ));
75 unavailable = true;
76 }
77 }
78
79 if !yaml.is_empty() {
80 if which("yq").is_some() {
81 for f in &yaml {
82 if is_helm_template(&root, f) {
83 continue;
84 }
85 if !parses(&root, "yq", &["e", "true", "--", f]) {
88 fail(&format!("Invalid YAML: {}", hl(f)));
89 failed = true;
90 }
91 }
92 } else {
93 warn(&format!(
94 "YAML files detected. To lint them, install {}",
95 hl("yq")
96 ));
97 unavailable = true;
98 }
99 }
100
101 match (failed, unavailable) {
102 (true, _) => Outcome::Failed,
103 (false, true) => Outcome::Unavailable,
104 (false, false) => {
105 ok("Json/Yaml Lint passed");
106 Outcome::Passed
107 }
108 }
109}