1#[derive(Copy, Clone, PartialEq, Eq, Debug)]
2pub enum CiEnv {
3/// Not a CI environment.
4None,
5/// The GitHub Actions environment, for Linux (including Docker), Windows and macOS builds.
6GitHubActions,
7}
89impl CiEnv {
10/// Obtains the current CI environment.
11pub fn current() -> CiEnv {
12if std::env::var("GITHUB_ACTIONS").map_or(false, |e| e == "true") {
13 CiEnv::GitHubActions
14 } else {
15 CiEnv::None
16 }
17 }
1819pub fn is_ci() -> bool {
20Self::current() != CiEnv::None
21 }
2223/// Checks if running in rust-lang/rust managed CI job.
24pub fn is_rust_lang_managed_ci_job() -> bool {
25Self::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}
3233pub mod gha {
34use std::sync::Mutex;
3536static ACTIVE_GROUPS: Mutex<Vec<String>> = Mutex::new(Vec::new());
3738/// 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]
43pub fn group(name: impl std::fmt::Display) -> Group {
44let mut groups = ACTIVE_GROUPS.lock().unwrap();
4546// A group is currently active. End it first to avoid nesting.
47if !groups.is_empty() {
48 end_group();
49 }
5051let name = name.to_string();
52 start_group(&name);
53 groups.push(name);
54 Group(())
55 }
5657/// A guard that closes the current github actions log group on drop.
58#[must_use]
59pub struct Group(());
6061impl Drop for Group {
62fn drop(&mut self) {
63 end_group();
6465let mut groups = ACTIVE_GROUPS.lock().unwrap();
66// Remove the current group
67groups.pop();
6869// If there was some previous group, restart it
70if is_in_gha() {
71if let Some(name) = groups.last() {
72 start_group(format!("{name} (continued)"));
73 }
74 }
75 }
76 }
7778fn start_group(name: impl std::fmt::Display) {
79if is_in_gha() {
80println!("::group::{name}");
81 } else {
82println!("{name}")
83 }
84 }
8586fn end_group() {
87if is_in_gha() {
88println!("::endgroup::");
89 }
90 }
9192fn is_in_gha() -> bool {
93 std::env::var_os("GITHUB_ACTIONS").is_some()
94 }
95}