lint_docs.rs raw

   1  // Copyright (c) The Bitcoin Core developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or https://opensource.org/license/mit/.
   4  
   5  use std::io::ErrorKind;
   6  use std::process::{Command, Stdio};
   7  
   8  use crate::util::{check_output, get_subtrees, git, LintResult};
   9  
  10  pub fn lint_doc_release_note_snippets() -> LintResult {
  11      let non_release_notes = check_output(git().args([
  12          "ls-files",
  13          "--",
  14          "doc/release-notes/",
  15          ":(exclude)doc/release-notes/*.*.md", // Assume that at least one dot implies a proper release note
  16      ]))?;
  17      if non_release_notes.is_empty() {
  18          Ok(())
  19      } else {
  20          println!("{non_release_notes}");
  21          Err(r#"
  22  Release note snippets and other docs must be put into the doc/ folder directly.
  23  
  24  The doc/release-notes/ folder is for archived release notes of previous releases only. Snippets are
  25  expected to follow the naming "/doc/release-notes-<PR number>.md".
  26              "#
  27          .trim()
  28          .to_string())
  29      }
  30  }
  31  
  32  pub fn lint_doc_args() -> LintResult {
  33      if Command::new("test/lint/check-doc.py")
  34          .status()
  35          .expect("command error")
  36          .success()
  37      {
  38          Ok(())
  39      } else {
  40          Err("".to_string())
  41      }
  42  }
  43  
  44  pub fn lint_markdown() -> LintResult {
  45      let bin_name = "mlc";
  46      let mut md_ignore_paths = get_subtrees();
  47      md_ignore_paths.push("./doc/README_doxygen.md");
  48      let md_ignore_path_str = md_ignore_paths.join(",");
  49  
  50      let mut cmd = Command::new(bin_name);
  51      cmd.args([
  52          "--offline",
  53          "--ignore-path",
  54          md_ignore_path_str.as_str(),
  55          "--gitignore",
  56          "--gituntracked",
  57          "--root-dir",
  58          ".",
  59      ])
  60      .stdout(Stdio::null()); // Suppress overly-verbose output
  61  
  62      match cmd.output() {
  63          Ok(output) if output.status.success() => Ok(()),
  64          Ok(output) => {
  65              let stderr = String::from_utf8_lossy(&output.stderr);
  66              Err(format!(
  67                  r#"
  68  One or more markdown links are broken.
  69  
  70  Note: relative links are preferred as jump-to-file works natively within Emacs, but they are not required.
  71  
  72  Markdown link errors found:
  73  {stderr}
  74                  "#
  75              )
  76              .trim()
  77              .to_string())
  78          }
  79          Err(e) if e.kind() == ErrorKind::NotFound => {
  80              println!("`mlc` was not found in $PATH, skipping markdown lint check.");
  81              Ok(())
  82          }
  83          Err(e) => Err(format!("Error running mlc: {e}")), // Misc errors
  84      }
  85  }
  86