11package com .databricks .sdk .core ;
22
3+ import com .databricks .sdk .core .utils .Environment ;
4+ import java .io .File ;
35import java .util .ArrayList ;
6+ import java .util .Arrays ;
7+ import java .util .Collections ;
48import java .util .List ;
59import java .util .regex .Pattern ;
610import java .util .stream .Collectors ;
@@ -121,6 +125,10 @@ public static String asString() {
121125 segments .add (String .format ("databricks-sdk-java/%s" , version ));
122126 segments .add (String .format ("jvm/%s" , jvmVersion ()));
123127 segments .add (String .format ("os/%s" , osName ()));
128+ String cicdProvider = cicdProvider ();
129+ if (!cicdProvider .isEmpty ()) {
130+ segments .add (String .format ("cicd/%s" , cicdProvider ));
131+ }
124132 // Concurrent iteration over ArrayList must be guarded with synchronized.
125133 synchronized (otherInfo ) {
126134 segments .addAll (
@@ -130,4 +138,107 @@ public static String asString() {
130138 }
131139 return segments .stream ().collect (Collectors .joining (" " ));
132140 }
141+
142+ // List of CI/CD providers and their environment variables for detection
143+ private static List <CicdProvider > listCiCdProviders () {
144+ return Arrays .asList (
145+ new CicdProvider ("github" , Collections .singletonList (new EnvVar ("GITHUB_ACTIONS" , "true" ))),
146+ new CicdProvider ("gitlab" , Collections .singletonList (new EnvVar ("GITLAB_CI" , "true" ))),
147+ new CicdProvider ("jenkins" , Collections .singletonList (new EnvVar ("JENKINS_URL" , "" ))),
148+ new CicdProvider ("azure-devops" , Collections .singletonList (new EnvVar ("TF_BUILD" , "True" ))),
149+ new CicdProvider ("circle" , Collections .singletonList (new EnvVar ("CIRCLECI" , "true" ))),
150+ new CicdProvider ("travis" , Collections .singletonList (new EnvVar ("TRAVIS" , "true" ))),
151+ new CicdProvider (
152+ "bitbucket" , Collections .singletonList (new EnvVar ("BITBUCKET_BUILD_NUMBER" , "" ))),
153+ new CicdProvider (
154+ "google-cloud-build" ,
155+ Arrays .asList (
156+ new EnvVar ("PROJECT_ID" , "" ),
157+ new EnvVar ("BUILD_ID" , "" ),
158+ new EnvVar ("PROJECT_NUMBER" , "" ),
159+ new EnvVar ("LOCATION" , "" ))),
160+ new CicdProvider (
161+ "aws-code-build" , Collections .singletonList (new EnvVar ("CODEBUILD_BUILD_ARN" , "" ))),
162+ new CicdProvider ("tf-cloud" , Collections .singletonList (new EnvVar ("TFC_RUN_ID" , "" ))));
163+ }
164+
165+ // Volatile field to ensure thread-safe lazy initialization
166+ // The 'volatile' keyword ensures that changes to these variables
167+ // are immediately visible to all threads. It prevents instruction
168+ // reordering by the compiler.
169+ protected static volatile String cicdProvider = null ;
170+
171+ protected static Environment env = null ;
172+
173+ // Represents an environment variable with its name and expected value
174+ private static class EnvVar {
175+ private final String name ;
176+ private final String expectedValue ;
177+
178+ public EnvVar (String name , String expectedValue ) {
179+ this .name = name ;
180+ this .expectedValue = expectedValue ;
181+ }
182+ }
183+
184+ // Represents a CI/CD provider with its name and associated environment variables
185+ private static class CicdProvider {
186+ private final String name ;
187+ private final List <EnvVar > envVars ;
188+
189+ public CicdProvider (String name , List <EnvVar > envVars ) {
190+ this .name = name ;
191+ this .envVars = envVars ;
192+ }
193+
194+ public boolean detect (Environment env ) {
195+ for (EnvVar envVar : envVars ) {
196+ String value = env .get (envVar .name );
197+ if (value == null ) {
198+ return false ;
199+ }
200+ if (!envVar .expectedValue .isEmpty () && !value .equals (envVar .expectedValue )) {
201+ return false ;
202+ }
203+ }
204+ return true ;
205+ }
206+ }
207+
208+ // Looks up the active CI/CD provider based on environment variables
209+ private static String lookupCiCdProvider (Environment env ) {
210+ for (CicdProvider provider : listCiCdProviders ()) {
211+ if (provider .detect (env )) {
212+ return provider .name ;
213+ }
214+ }
215+ return "" ;
216+ }
217+
218+ // Thread-safe lazy initialization of CI/CD provider detection
219+ private static String cicdProvider () {
220+ // First check (not synchronized) to avoid unnecessary synchronization
221+ if (cicdProvider == null ) {
222+ // Synchronize only if cicdProvider is null
223+ synchronized (UserAgent .class ) {
224+ // Second check (synchronized) to ensure only one thread initializes
225+ // This is necessary because multiple threads might have passed the first check
226+ if (cicdProvider == null ) {
227+ cicdProvider = lookupCiCdProvider (env ());
228+ }
229+ }
230+ }
231+ return cicdProvider ;
232+ }
233+
234+ private static Environment env () {
235+ if (env == null ) {
236+ env =
237+ new Environment (
238+ System .getenv (),
239+ System .getenv ("PATH" ).split (File .pathSeparator ),
240+ System .getProperty ("os.name" ));
241+ }
242+ return env ;
243+ }
133244}
0 commit comments