diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 5c69714bc1e9..5553e8ae5ad2 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -203,6 +203,7 @@ jobs: max-parallel: 6 matrix: integration: + - 'rust-lang/rust' - 'rust-lang/cargo' - 'rust-lang/chalk' - 'rust-lang/rustfmt' diff --git a/tests/integration.rs b/tests/integration.rs index 031982edbe9e..d4de8281e6f2 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -23,6 +23,11 @@ const CARGO_CLIPPY: &str = "cargo-clippy.exe"; #[cfg_attr(feature = "integration", test)] fn integration_test() { let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set"); + + if repo_name == "rust-lang/rust" { + return; + } + let repo_url = format!("https://github.com/{repo_name}"); let crate_name = repo_name .split('/') @@ -123,3 +128,135 @@ fn integration_test() { None => panic!("Process terminated by signal"), } } + +#[cfg_attr(feature = "integration", test)] +fn integration_test_rustc() { + let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set"); + + if repo_name != "rust-lang/rust" { + return; + } + + let repo_url = format!("https://github.com/{repo_name}"); + let crate_name = repo_name + .split('/') + .nth(1) + .expect("repo name should have format `/`"); + + let mut repo_dir = tempfile::tempdir().expect("couldn't create temp dir").into_path(); + repo_dir.push(crate_name); + + let st_git_cl = Command::new("git") + .args([ + OsStr::new("clone"), + OsStr::new("--depth=5000"), + OsStr::new(&repo_url), + OsStr::new(&repo_dir), + ]) + .status() + .expect("unable to run git"); + assert!(st_git_cl.success()); + + // clippy is pinned to a specific nightly version + // check out the commit of that nightly to ensure compatibility + let rustc_output = Command::new("rustc") + .arg("--version") + .arg("--verbose") + .output() + .expect("failed to run rustc --version"); + + let commit_line = String::from_utf8_lossy(rustc_output.stdout); + let commit_line_ = commit_line + .lines() + .find(|line| line.starts_with("commit-hash: ")) + .expect("did not find 'commit-hash:' in --version output"); + + let commit = commit_line_ + .strip_prefix("commit-hash: ") + .expect("failed parsing commit line"); + + // check out the commit in the rustc repo to ensure clippy is compatible + + let st_git_checkout = Command::new("git") + .arg("checkout") + .arg(commit) + .status() + .expect("git failed to check out commit"); + assert!(st_git_checkout.success()); + + let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let target_dir = std::path::Path::new(&root_dir).join("target"); + let clippy_binary = target_dir.join(env!("PROFILE")).join(CARGO_CLIPPY); + + // we need to make sure that `x.py clippy` picks up our self-built clippy + // try to make the target dir discoverable as PATH + + let path_env = target_dir.join(env!("PROFILE")); + + let output = Command::new("x.py") + .current_dir("rust") + .env("RUST_BACKTRACE", "full") + .env("PATH", path_env) + .args(["clippy", "-Wclippy::pedantic", "-Wclippy::nursery"]) + .output() + .expect("unable to run x.py clippy"); + + let stderr = String::from_utf8_lossy(&output.stderr); + + // debug: + eprintln!("{stderr}"); + + // this is an internal test to make sure we would correctly panic on a delay_span_bug + if repo_name == "matthiaskrgr/clippy_ci_panic_test" { + // we need to kind of switch around our logic here: + // if we find a panic, everything is fine, if we don't panic, SOMETHING is broken about our testing + + // the repo basically just contains a delay_span_bug that forces rustc/clippy to panic: + /* + #![feature(rustc_attrs)] + #[rustc_error(delay_span_bug_from_inside_query)] + fn main() {} + */ + + if stderr.find("error: internal compiler error").is_some() { + eprintln!("we saw that we intentionally panicked, yay"); + return; + } + + panic!("panic caused by delay_span_bug was NOT detected! Something is broken!"); + } + + if let Some(backtrace_start) = stderr.find("error: internal compiler error") { + static BACKTRACE_END_MSG: &str = "end of query stack"; + let backtrace_end = stderr[backtrace_start..] + .find(BACKTRACE_END_MSG) + .expect("end of backtrace not found"); + + panic!( + "internal compiler error\nBacktrace:\n\n{}", + &stderr[backtrace_start..backtrace_start + backtrace_end + BACKTRACE_END_MSG.len()] + ); + } else if stderr.contains("query stack during panic") { + panic!("query stack during panic in the output"); + } else if stderr.contains("E0463") { + // Encountering E0463 (can't find crate for `x`) did _not_ cause the build to fail in the + // past. Even though it should have. That's why we explicitly panic here. + // See PR #3552 and issue #3523 for more background. + panic!("error: E0463"); + } else if stderr.contains("E0514") { + panic!("incompatible crate versions"); + } else if stderr.contains("failed to run `rustc` to learn about target-specific information") { + panic!("couldn't find librustc_driver, consider setting `LD_LIBRARY_PATH`"); + } else { + assert!( + !stderr.contains("toolchain") || !stderr.contains("is not installed"), + "missing required toolchain" + ); + } + + match output.status.code() { + Some(0) => println!("Compilation successful"), + Some(code) => eprintln!("Compilation failed. Exit code: {code}"), + None => panic!("Process terminated by signal"), + } +}