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
44pub 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
52pub 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
123pub 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
175pub 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}