build_helper/ci.rs
1#[derive(Copy, Clone, PartialEq, Eq, Debug)]
2pub enum CiEnv {
3 /// Not a CI environment.
4 None,
5 /// The GitHub Actions environment, for Linux (including Docker), Windows and macOS builds.
6 GitHubActions,
7}
8
9impl CiEnv {
10 /// Obtains the current CI environment.
11 pub fn current() -> CiEnv {
12 if std::env::var("GITHUB_ACTIONS").map_or(false, |e| e == "true") {
13 CiEnv::GitHubActions
14 } else {
15 CiEnv::None
16 }
17 }
18
19 pub fn is_ci() -> bool {
20 Self::current() != CiEnv::None
21 }
22
23 /// Checks if running in rust-lang/rust managed CI job.
24 pub fn is_rust_lang_managed_ci_job() -> bool {
25 Self::is_ci()
26 // If both are present, we can assume it's an upstream CI job
27 // as they are always set unconditionally.
28 && std::env::var_os("CI_JOB_NAME").is_some()
29 && std::env::var_os("TOOLSTATE_REPO").is_some()
30 }
31}
32
33pub mod gha {
34 use std::sync::Mutex;
35
36 static ACTIVE_GROUPS: Mutex<Vec<String>> = Mutex::new(Vec::new());
37
38 /// All github actions log messages from this call to the Drop of the return value
39 /// will be grouped and hidden by default in logs. Note that since github actions doesn't
40 /// support group nesting, any active group will be first finished when a subgroup is started,
41 /// and then re-started when the subgroup finishes.
42 #[track_caller]
43 pub fn group(name: impl std::fmt::Display) -> Group {
44 let mut groups = ACTIVE_GROUPS.lock().unwrap();
45
46 // A group is currently active. End it first to avoid nesting.
47 if !groups.is_empty() {
48 end_group();
49 }
50
51 let name = name.to_string();
52 start_group(&name);
53 groups.push(name);
54 Group(())
55 }
56
57 /// A guard that closes the current github actions log group on drop.
58 #[must_use]
59 pub struct Group(());
60
61 impl Drop for Group {
62 fn drop(&mut self) {
63 end_group();
64
65 let mut groups = ACTIVE_GROUPS.lock().unwrap();
66 // Remove the current group
67 groups.pop();
68
69 // If there was some previous group, restart it
70 if is_in_gha() {
71 if let Some(name) = groups.last() {
72 start_group(format!("{name} (continued)"));
73 }
74 }
75 }
76 }
77
78 fn start_group(name: impl std::fmt::Display) {
79 if is_in_gha() {
80 println!("::group::{name}");
81 } else {
82 println!("{name}")
83 }
84 }
85
86 fn end_group() {
87 if is_in_gha() {
88 println!("::endgroup::");
89 }
90 }
91
92 fn is_in_gha() -> bool {
93 std::env::var_os("GITHUB_ACTIONS").is_some()
94 }
95}