diff --git a/src/build_helper/src/ci.rs b/src/build_helper/src/ci.rs index 60f319129a0bd..9d114c70a671b 100644 --- a/src/build_helper/src/ci.rs +++ b/src/build_helper/src/ci.rs @@ -17,7 +17,11 @@ impl CiEnv { } pub fn is_ci() -> bool { - Self::current() != CiEnv::None + Self::current().is_running_in_ci() + } + + pub fn is_running_in_ci(self) -> bool { + self != CiEnv::None } /// Checks if running in rust-lang/rust managed CI job. diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 438cd14389c1c..9d1195aadf848 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -198,7 +198,7 @@ fn get_latest_upstream_commit_that_modified_files( /// author. /// /// If we are in CI, we simply return our first parent. -fn get_closest_upstream_commit( +pub fn get_closest_upstream_commit( git_dir: Option<&Path>, config: &GitConfig<'_>, env: CiEnv, diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index e8a12d563358d..28aa80225b177 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -83,6 +83,7 @@ pub mod pal; pub mod rustdoc_css_themes; pub mod rustdoc_gui_tests; pub mod rustdoc_js; +pub mod rustdoc_json; pub mod rustdoc_templates; pub mod style; pub mod target_policy; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 776f1bde2eb71..0b66017b86522 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -110,6 +110,7 @@ fn main() { check!(rustdoc_css_themes, &librustdoc_path); check!(rustdoc_templates, &librustdoc_path); check!(rustdoc_js, &librustdoc_path, &tools_path, &src_path); + check!(rustdoc_json, &src_path); check!(known_bug, &crashes_path); check!(unknown_revision, &tests_path); diff --git a/src/tools/tidy/src/rustdoc_json.rs b/src/tools/tidy/src/rustdoc_json.rs new file mode 100644 index 0000000000000..f179acf4a5106 --- /dev/null +++ b/src/tools/tidy/src/rustdoc_json.rs @@ -0,0 +1,101 @@ +//! Tidy check to ensure that `FORMAT_VERSION` was correctly updated if `rustdoc-json-types` was +//! updated as well. + +use std::ffi::OsStr; +use std::path::Path; +use std::process::Command; + +use build_helper::ci::CiEnv; +use build_helper::git::{GitConfig, get_closest_upstream_commit}; +use build_helper::stage0_parser::parse_stage0_file; + +const RUSTDOC_JSON_TYPES: &str = "src/rustdoc-json-types"; + +fn git_diff>(base_commit: &str, extra_arg: S) -> Option { + let output = Command::new("git").arg("diff").arg(base_commit).arg(extra_arg).output().ok()?; + Some(String::from_utf8_lossy(&output.stdout).into()) +} + +fn error_if_in_ci(ci_env: CiEnv, msg: &str, bad: &mut bool) { + if ci_env.is_running_in_ci() { + *bad = true; + eprintln!("error in `rustdoc_json` tidy check: {msg}"); + } else { + eprintln!("{msg}. Skipping `rustdoc_json` tidy check"); + } +} + +pub fn check(src_path: &Path, bad: &mut bool) { + println!("Checking tidy rustdoc_json..."); + let stage0 = parse_stage0_file(); + let ci_env = CiEnv::current(); + let base_commit = match get_closest_upstream_commit( + None, + &GitConfig { + nightly_branch: &stage0.config.nightly_branch, + git_merge_commit_email: &stage0.config.git_merge_commit_email, + }, + ci_env, + ) { + Ok(Some(commit)) => commit, + Ok(None) => { + error_if_in_ci(ci_env, "no base commit found", bad); + return; + } + Err(error) => { + error_if_in_ci(ci_env, &format!("failed to retrieve base commit: {error}"), bad); + return; + } + }; + + // First we check that `src/rustdoc-json-types` was modified. + match git_diff(&base_commit, "--name-status") { + Some(output) => { + if !output + .lines() + .any(|line| line.starts_with("M") && line.contains(RUSTDOC_JSON_TYPES)) + { + // `rustdoc-json-types` was not modified so nothing more to check here. + println!("`rustdoc-json-types` was not modified."); + return; + } + } + None => { + *bad = true; + eprintln!("error: failed to run `git diff` in rustdoc_json check"); + return; + } + } + // Then we check that if `FORMAT_VERSION` was updated, the `Latest feature:` was also updated. + match git_diff(&base_commit, src_path.join("rustdoc-json-types")) { + Some(output) => { + let mut format_version_updated = false; + let mut latest_feature_comment_updated = false; + for line in output.lines() { + if line.starts_with("+pub const FORMAT_VERSION: u32 =") { + format_version_updated = true; + } else if line.starts_with("+// Latest feature:") { + latest_feature_comment_updated = true; + } + } + if format_version_updated != latest_feature_comment_updated { + *bad = true; + if latest_feature_comment_updated { + eprintln!( + "error in `rustdoc_json` tidy check: `Latest feature` comment was updated \ + whereas `FORMAT_VERSION` wasn't in `{RUSTDOC_JSON_TYPES}/lib.rs`" + ); + } else { + eprintln!( + "error in `rustdoc_json` tidy check: `Latest feature` comment was not \ + updated whereas `FORMAT_VERSION` was in `{RUSTDOC_JSON_TYPES}/lib.rs`" + ); + } + } + } + None => { + *bad = true; + eprintln!("error: failed to run `git diff` in rustdoc_json check"); + } + } +}