Skip to content

Commit e8bf8fb

Browse files
committed
Auto merge of #11235 - matthiaskrgr:rustc_in_ci, r=<try>
[blocked] attempt to check rust-lang/rust with clippy in ci r? `@ghost` changelog: run clippy on rust-lang/rust as integration test This might be blocked on at least #11230 #11176 #11256
2 parents 75370e0 + 1f7d797 commit e8bf8fb

File tree

2 files changed

+171
-1
lines changed

2 files changed

+171
-1
lines changed

.github/workflows/clippy_bors.yml

+1
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ jobs:
203203
max-parallel: 6
204204
matrix:
205205
integration:
206+
- 'rust-lang/rust'
206207
- 'rust-lang/cargo'
207208
- 'rust-lang/chalk'
208209
- 'rust-lang/rustfmt'

tests/integration.rs

+170-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
1212
#![warn(rust_2018_idioms, unused_lifetimes)]
1313

14-
use std::env;
1514
use std::ffi::OsStr;
15+
use std::path::PathBuf;
1616
use std::process::Command;
17+
use std::{env, fs};
1718

1819
#[cfg(not(windows))]
1920
const CARGO_CLIPPY: &str = "cargo-clippy";
@@ -23,6 +24,11 @@ const CARGO_CLIPPY: &str = "cargo-clippy.exe";
2324
#[cfg_attr(feature = "integration", test)]
2425
fn integration_test() {
2526
let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set");
27+
28+
if repo_name == "rust-lang/rust" {
29+
return;
30+
}
31+
2632
let repo_url = format!("https://github.com/{repo_name}");
2733
let crate_name = repo_name
2834
.split('/')
@@ -123,3 +129,166 @@ fn integration_test() {
123129
None => panic!("Process terminated by signal"),
124130
}
125131
}
132+
133+
#[allow(clippy::too_many_lines)]
134+
#[cfg_attr(feature = "integration", test)]
135+
fn integration_test_rustc() {
136+
let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set");
137+
138+
// try to avoid running this test locally
139+
if !(repo_name == "rust-lang/rust" && env::var("GITHUB_ACTIONS") == Ok(String::from("true"))) {
140+
return;
141+
}
142+
143+
println!("getting rustc version");
144+
// clippy is pinned to a specific nightly version
145+
// check out the commit of that nightly to ensure compatibility
146+
let rustc_output = Command::new("rustc")
147+
.arg("--version")
148+
.arg("--verbose")
149+
.output()
150+
.expect("failed to run rustc --version");
151+
152+
let rustc_output_string = String::from_utf8_lossy(&rustc_output.stdout);
153+
let commit_line = rustc_output_string
154+
.lines()
155+
.find(|line| line.starts_with("commit-hash: "))
156+
.expect("did not find 'commit-hash: ' in --version output");
157+
158+
let commit = commit_line
159+
.strip_prefix("commit-hash: ")
160+
.expect("failed parsing commit line");
161+
162+
let repo_url = format!("https://github.com/{repo_name}");
163+
let crate_name = repo_name
164+
.split('/')
165+
.nth(1)
166+
.expect("repo name should have format `<org>/<name>`");
167+
168+
let mut repo_dir = tempfile::tempdir().expect("couldn't create temp dir").into_path();
169+
repo_dir.push(crate_name);
170+
171+
println!("cloning git repo");
172+
let st_git_cl = Command::new("git")
173+
.args([
174+
OsStr::new("clone"),
175+
// we can't use depth=x because we don't know how far away the master branc tip is from our nightly commit
176+
// that we need.
177+
// however, we can still gain a lot by using --filter=tree:0 which is still ~10x faster than a full clone
178+
179+
// https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/
180+
OsStr::new("--filter=tree:0"),
181+
OsStr::new(&repo_url),
182+
OsStr::new(&repo_dir),
183+
])
184+
.status()
185+
.expect("unable to run git clone");
186+
assert!(st_git_cl.success());
187+
188+
// check out the commit in the rustc repo to ensure clippy is compatible with std/core and the
189+
// compiler internals
190+
191+
println!("checking out commit '{commit}' in rustc repo");
192+
let st_git_checkout = Command::new("git")
193+
.current_dir(&repo_dir)
194+
.arg("checkout")
195+
.arg(commit)
196+
.status()
197+
.expect("git failed to check out commit '{commit}' in rustc repo");
198+
assert!(st_git_checkout.success());
199+
200+
let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
201+
let target_dir = std::path::Path::new(&root_dir).join("target");
202+
// the clippy binary is in there
203+
let clippy_exec_dir = target_dir.join(env!("PROFILE"));
204+
205+
// we want that `x.py clippy` picks up our self-built clippy for testing!
206+
// copy the clippy we built earlier into the toolchain directory of the nightly
207+
// that clippy is pinned, so that x.py can pick it up and use it
208+
209+
// copy our own clippy binary into the rustc toolchain dir so that x.py finds them:
210+
// get the sysroot path from nightly and put our binaries into ${sysroot}/bin/
211+
let sysroot_output = Command::new("rustc")
212+
.arg("--print")
213+
.arg("sysroot")
214+
.output()
215+
.expect("rustc failed to print sysroot");
216+
// trim away the "\n" at the end because we don't want this in our Path :D
217+
let untrimmed = String::from_utf8_lossy(&sysroot_output.stdout).to_string();
218+
let sysroot_trimmed = untrimmed.trim();
219+
let mut sysroot = sysroot_trimmed.to_string();
220+
sysroot.push('/');
221+
let sysroot_path = PathBuf::from(sysroot);
222+
223+
assert!(
224+
sysroot_path.exists(),
225+
"{}",
226+
format!("sysroot path '{}' not found!", sysroot_path.display())
227+
);
228+
229+
let sysroot_bin_dir = sysroot_path.join("bin");
230+
eprintln!("clippy binaries will be put int {}", sysroot_bin_dir.display());
231+
232+
// copy files from target dir into our $sysroot/bin
233+
std::fs::read_dir(clippy_exec_dir)
234+
.expect("failed to read clippys target/ dir that we downloaded from previous ci step")
235+
.map(|entry| entry.expect("DirEntry not ok"))
236+
.map(|entry| entry.path())
237+
.filter(|path| path.is_file())
238+
.for_each(|clippy_binary| {
239+
let new_base: PathBuf = sysroot_bin_dir.join("willbeoverwritten"); // file_name() will overwrite this
240+
// set the path from /foo/dir/willbeoverwritten to /foo/dir/cargo-clippy
241+
let bin_file_name: &std::ffi::OsStr = clippy_binary.file_name().unwrap();
242+
let new_path: PathBuf = new_base.with_file_name(bin_file_name);
243+
244+
fs::copy(dbg!(clippy_binary), dbg!(new_path))
245+
.expect("could not copy file from '{clippy_binary}' to '{new_path}'");
246+
});
247+
248+
// some notes: x.py will set --cap-lints warn by default
249+
let output = Command::new("python")
250+
.arg("./x.py")
251+
.current_dir(&repo_dir)
252+
.env("RUST_BACKTRACE", "full")
253+
.args(["clippy", "-Wclippy::pedantic", "-Wclippy::cargo"])
254+
.output()
255+
.expect("unable to run x.py clippy");
256+
257+
let stderr = String::from_utf8_lossy(&output.stderr);
258+
259+
eprintln!("{stderr}");
260+
261+
if let Some(backtrace_start) = stderr.find("error: internal compiler error") {
262+
static BACKTRACE_END_MSG: &str = "end of query stack";
263+
let backtrace_end = stderr[backtrace_start..]
264+
.find(BACKTRACE_END_MSG)
265+
.expect("end of backtrace not found");
266+
267+
panic!(
268+
"internal compiler error\nBacktrace:\n\n{}",
269+
&stderr[backtrace_start..backtrace_start + backtrace_end + BACKTRACE_END_MSG.len()]
270+
);
271+
} else if stderr.contains("query stack during panic") {
272+
panic!("query stack during panic in the output");
273+
} else if stderr.contains("E0463") {
274+
// Encountering E0463 (can't find crate for `x`) did _not_ cause the build to fail in the
275+
// past. Even though it should have. That's why we explicitly panic here.
276+
// See PR #3552 and issue #3523 for more background.
277+
panic!("error: E0463");
278+
} else if stderr.contains("E0514") {
279+
panic!("incompatible crate versions");
280+
} else if stderr.contains("failed to run `rustc` to learn about target-specific information") {
281+
panic!("couldn't find librustc_driver, consider setting `LD_LIBRARY_PATH`");
282+
} else {
283+
assert!(
284+
!stderr.contains("toolchain") || !stderr.contains("is not installed"),
285+
"missing required toolchain"
286+
);
287+
}
288+
289+
match output.status.code() {
290+
Some(0) => println!("Compilation successful"),
291+
Some(code) => eprintln!("Compilation failed. Exit code: {code}"),
292+
None => panic!("Process terminated by signal"),
293+
}
294+
}

0 commit comments

Comments
 (0)