tidy/
rustdoc_json.rs

1//! Tidy check to ensure that `FORMAT_VERSION` was correctly updated if `rustdoc-json-types` was
2//! updated as well.
3
4use std::path::Path;
5use std::str::FromStr;
6
7use crate::diagnostics::{CheckId, DiagCtx};
8
9const RUSTDOC_JSON_TYPES: &str = "src/rustdoc-json-types";
10
11pub fn check(src_path: &Path, ci_info: &crate::CiInfo, diag_ctx: DiagCtx) {
12    let mut check = diag_ctx.start_check(CheckId::new("rustdoc_json").path(src_path));
13
14    let Some(base_commit) = &ci_info.base_commit else {
15        check.verbose_msg("No base commit, skipping rustdoc_json check");
16        return;
17    };
18
19    // First we check that `src/rustdoc-json-types` was modified.
20    if !crate::files_modified(ci_info, |p| p.starts_with(RUSTDOC_JSON_TYPES)) {
21        // `rustdoc-json-types` was not modified so nothing more to check here.
22        return;
23    }
24
25    check.message("`rustdoc-json-types` modified, checking format version");
26
27    // Then we check that if `FORMAT_VERSION` was updated, the `Latest feature:` was also updated.
28    match crate::git_diff(base_commit, src_path.join("rustdoc-json-types")) {
29        Some(output) => {
30            let mut format_version_updated = false;
31            let mut latest_feature_comment_updated = false;
32            let mut new_version = None;
33            let mut old_version = None;
34            for line in output.lines() {
35                if line.starts_with("+pub const FORMAT_VERSION: u32 =") {
36                    format_version_updated = true;
37                    new_version = line
38                        .split('=')
39                        .nth(1)
40                        .and_then(|s| s.trim().split(';').next())
41                        .and_then(|s| u32::from_str(s.trim()).ok());
42                } else if line.starts_with("-pub const FORMAT_VERSION: u32 =") {
43                    old_version = line
44                        .split('=')
45                        .nth(1)
46                        .and_then(|s| s.trim().split(';').next())
47                        .and_then(|s| u32::from_str(s.trim()).ok());
48                } else if line.starts_with("+// Latest feature:") {
49                    latest_feature_comment_updated = true;
50                }
51            }
52            if format_version_updated != latest_feature_comment_updated {
53                let msg = if latest_feature_comment_updated {
54                    format!(
55                        "`Latest feature` comment was updated whereas `FORMAT_VERSION` wasn't in `{RUSTDOC_JSON_TYPES}/lib.rs`"
56                    )
57                } else {
58                    format!(
59                        "`Latest feature` comment was not updated whereas `FORMAT_VERSION` was in `{RUSTDOC_JSON_TYPES}/lib.rs`"
60                    )
61                };
62                check.error(msg);
63            }
64            match (new_version, old_version) {
65                (Some(new_version), Some(old_version)) if new_version != old_version + 1 => {
66                    check.error(format!(
67                        "invalid `FORMAT_VERSION` increase in `{RUSTDOC_JSON_TYPES}/lib.rs`, should be `{}`, found `{new_version}`",
68                        old_version + 1,
69                    ));
70                }
71                _ => {}
72            }
73        }
74        None => {
75            check.error("failed to run `git diff` in rustdoc_json check");
76        }
77    }
78}