ci_env/
lib.rs

1mod agola;
2mod api;
3mod appcenter;
4mod appcircle;
5mod appveyor;
6mod aws_codebuild;
7mod azure;
8mod bamboo;
9mod bitbucket;
10mod bitrise;
11mod buddy;
12mod buildkite;
13mod circleci;
14mod cirrus;
15mod codefresh;
16mod codemagic;
17mod codeship;
18mod drone;
19mod eas;
20mod github;
21mod gitlab;
22mod google_cloud_build;
23mod harness;
24mod heroku;
25mod jenkins;
26mod jenkins_x;
27mod jetbrains_space;
28mod netlify;
29mod screwdriver;
30mod scrutinizer;
31mod semaphore;
32mod teamcity;
33mod travisci;
34mod vela;
35mod vercel;
36mod woodpecker;
37mod xcode_cloud;
38mod xcode_server;
39
40pub use api::{CiEnvironment, CiOutput, CiProvider};
41use std::env;
42use std::sync::OnceLock;
43
44/// Returns true if in a CI environment by checking for the existence of the `CI`
45/// environment variable. It does not validate the variable value.
46pub fn is_ci() -> bool {
47    env::var("CI").is_ok_and(|v| v == "1" || v == "true")
48}
49
50static PROVIDER: OnceLock<CiProvider> = OnceLock::new();
51
52/// Detects the CI provider by checking for the existence of environment variables
53/// specific to each provider. Returns `Unknown` if no provider is detected.
54pub fn detect_provider() -> CiProvider {
55    *PROVIDER.get_or_init(|| {
56        for (key, value) in env::vars() {
57            if value.is_empty() {
58                continue;
59            }
60
61            return match key.as_str() {
62                "CI" => {
63                    if value == "woodpecker" {
64                        CiProvider::Woodpecker
65                    } else {
66                        continue;
67                    }
68                }
69                "CI_NAME" => {
70                    if value == "codeship" {
71                        CiProvider::Codeship
72                    } else {
73                        continue;
74                    }
75                }
76                "AC_APPCIRCLE" => CiProvider::Appcircle,
77                "AGOLA_REPOSITORY_URL" => CiProvider::Agola,
78                "APPCENTER_BUILD_ID" => CiProvider::AppCenter,
79                "APPVEYOR" => CiProvider::AppVeyor,
80                "AZURE_PIPELINES" | "BUILD_BUILDURI" | "SYSTEM_TEAMFOUNDATIONCOLLECTIONURI" => {
81                    CiProvider::Azure
82                }
83                "BITBUCKET_WORKSPACE" | "BITBUCKET_COMMIT" => CiProvider::Bitbucket,
84                "BITRISE_IO" => CiProvider::Bitrise,
85                "BUDDY" | "BUDDY_WORKSPACE_ID" => CiProvider::Buddy,
86                "BUILDKITE" => CiProvider::Buildkite,
87                "CF_ACCOUNT" | "CF_BUILD_ID" => CiProvider::Codefresh,
88                "CIRCLECI" => CiProvider::CircleCI,
89                "CIRRUS_CI" => CiProvider::Cirrus,
90                "CI_XCODE_PROJECT" | "CI_XCODE_CLOUD" => CiProvider::XcodeCloud,
91                "CM_BUILD_ID" => CiProvider::Codemagic,
92                "CODEBUILD_BUILD_ARN" => CiProvider::AwsCodebuild,
93                "DRONE" => CiProvider::Drone,
94                "EAS_BUILD" => CiProvider::Eas,
95                "GITHUB_ACTIONS" => CiProvider::GithubActions,
96                "GITLAB_CI" => CiProvider::Gitlab,
97                "GOOGLE_CLOUD_BUILD" | "BUILDER_OUTPUT" => CiProvider::GoogleCloudBuild,
98                "HARNESS_BUILD_ID" => CiProvider::Harness,
99                "HEROKU_TEST_RUN_ID" => CiProvider::Heroku,
100                "JB_SPACE_EXECUTION_NUMBER" => CiProvider::JetbrainsSpace,
101                "JENKINS_URL" | "BUILD_ID" => CiProvider::Jenkins,
102                "JENKINS_X_URL" => CiProvider::JenkinsX,
103                "NETLIFY" => CiProvider::Netlify,
104                "SCREWDRIVER" => CiProvider::Screwdriver,
105                "SCRUTINIZER" => CiProvider::Scrutinizer,
106                "SEMAPHORE" => CiProvider::Semaphore,
107                "TEAMCITY_VERSION" => CiProvider::TeamCity,
108                "TRAVIS" => CiProvider::TravisCI,
109                "VELA" => CiProvider::Vela,
110                "VERCEL" | "NOW_BUILDER" => CiProvider::Vercel,
111                "XCS" => CiProvider::XcodeServer,
112                "bamboo_planKey" | "BAMBOO_PLANKEY" => CiProvider::Bamboo,
113                _ => {
114                    continue;
115                }
116            };
117        }
118
119        CiProvider::Unknown
120    })
121}
122
123/// Returns metadata and information about the current CI environment and CI provider.
124pub fn get_environment() -> Option<CiEnvironment> {
125    if !is_ci() {
126        return None;
127    }
128
129    let environment = match detect_provider() {
130        CiProvider::Agola => agola::create_environment(),
131        CiProvider::AppCenter => appcenter::create_environment(),
132        CiProvider::Appcircle => appcircle::create_environment(),
133        CiProvider::AppVeyor => appveyor::create_environment(),
134        CiProvider::AwsCodebuild => aws_codebuild::create_environment(),
135        CiProvider::Azure => azure::create_environment(),
136        CiProvider::Bamboo => bamboo::create_environment(),
137        CiProvider::Bitbucket => bitbucket::create_environment(),
138        CiProvider::Bitrise => bitrise::create_environment(),
139        CiProvider::Buddy => buddy::create_environment(),
140        CiProvider::Buildkite => buildkite::create_environment(),
141        CiProvider::CircleCI => circleci::create_environment(),
142        CiProvider::Cirrus => cirrus::create_environment(),
143        CiProvider::Codefresh => codefresh::create_environment(),
144        CiProvider::Codemagic => codemagic::create_environment(),
145        CiProvider::Codeship => codeship::create_environment(),
146        CiProvider::Drone => drone::create_environment(),
147        CiProvider::Eas => eas::create_environment(),
148        CiProvider::GithubActions => github::create_environment(),
149        CiProvider::Gitlab => gitlab::create_environment(),
150        CiProvider::GoogleCloudBuild => google_cloud_build::create_environment(),
151        CiProvider::Harness => harness::create_environment(),
152        CiProvider::Heroku => heroku::create_environment(),
153        CiProvider::Jenkins => jenkins::create_environment(),
154        CiProvider::JenkinsX => jenkins_x::create_environment(),
155        CiProvider::JetbrainsSpace => jetbrains_space::create_environment(),
156        CiProvider::Netlify => netlify::create_environment(),
157        CiProvider::Screwdriver => screwdriver::create_environment(),
158        CiProvider::Scrutinizer => scrutinizer::create_environment(),
159        CiProvider::Semaphore => semaphore::create_environment(),
160        CiProvider::TeamCity => teamcity::create_environment(),
161        CiProvider::TravisCI => travisci::create_environment(),
162        CiProvider::Vela => vela::create_environment(),
163        CiProvider::Vercel => vercel::create_environment(),
164        CiProvider::Woodpecker => woodpecker::create_environment(),
165        CiProvider::XcodeCloud => xcode_cloud::create_environment(),
166        CiProvider::XcodeServer => xcode_server::create_environment(),
167        CiProvider::Unknown => {
168            return None;
169        }
170    };
171
172    Some(environment)
173}
174
175/// Returns the output format for the current CI provider.
176pub fn get_output() -> Option<CiOutput> {
177    match detect_provider() {
178        CiProvider::Azure => Some(azure::AZURE_OUTPUT),
179        CiProvider::Buildkite => Some(buildkite::BUILDKITE_OUTPUT),
180        CiProvider::GithubActions => Some(github::GITHUB_OUTPUT),
181        CiProvider::TeamCity => Some(teamcity::TEAMCITY_OUTPUT),
182        CiProvider::TravisCI => Some(travisci::TRAVISCI_OUTPUT),
183        _ => None,
184    }
185}