4141GLOBAL_SONARCLOUD_URL = "https://sonarcloud.io"
4242US_SONARCLOUD_URL = "https://sonarqube.us"
4343
44+ UNAUTHORIZED_STATUS_CODES = (401 , 403 )
45+
46+ ACCEPT_JSON = {"Accept" : "application/json" }
47+ ACCEPT_OCTET_STREAM = {"Accept" : "application/octet-stream" }
48+
4449
4550@dataclass (frozen = True )
4651class SQVersion :
@@ -92,7 +97,7 @@ def __post_init__(self):
9297
9398@dataclass (frozen = True )
9499class JRE :
95- id : str
100+ id : Optional [ str ]
96101 filename : str
97102 sha256 : str
98103 java_path : str
@@ -103,7 +108,7 @@ class JRE:
103108 @staticmethod
104109 def from_dict (dict : dict ) -> "JRE" :
105110 return JRE (
106- id = dict [ "id" ] ,
111+ id = dict . get ( "id" , None ) ,
107112 filename = dict ["filename" ],
108113 sha256 = dict ["sha256" ],
109114 java_path = dict ["javaPath" ],
@@ -182,6 +187,7 @@ def __call__(self, r):
182187class EngineInfo :
183188 filename : str
184189 sha256 : str
190+ download_url : Optional [str ] = None
185191
186192
187193class SonarQubeApi :
@@ -193,7 +199,7 @@ def __raise_exception(self, exception: Exception) -> NoReturn:
193199 if (
194200 isinstance (exception , requests .RequestException )
195201 and exception .response is not None
196- and exception .response .status_code == 401
202+ and exception .response .status_code in UNAUTHORIZED_STATUS_CODES
197203 ):
198204 raise SonarQubeApiUnauthroizedException .create_default (self .base_urls .base_url ) from exception
199205 else :
@@ -215,14 +221,14 @@ def get_analysis_version(self) -> SQVersion:
215221
216222 def get_analysis_engine (self ) -> EngineInfo :
217223 try :
218- res = requests .get (
219- f"{ self .base_urls .api_base_url } /analysis/engine" , headers = {"Accept" : "application/json" }, auth = self .auth
220- )
224+ res = requests .get (f"{ self .base_urls .api_base_url } /analysis/engine" , headers = ACCEPT_JSON , auth = self .auth )
221225 res .raise_for_status ()
222226 json = res .json ()
223227 if "filename" not in json or "sha256" not in json :
224228 raise SonarQubeApiException ("Invalid response from the server" )
225- return EngineInfo (filename = json ["filename" ], sha256 = json ["sha256" ])
229+ return EngineInfo (
230+ filename = json ["filename" ], sha256 = json ["sha256" ], download_url = json .get ("downloadUrl" , None )
231+ )
226232 except requests .RequestException as e :
227233 self .__raise_exception (e )
228234
@@ -234,7 +240,7 @@ def download_analysis_engine(self, handle: typing.BinaryIO) -> None:
234240 try :
235241 res = requests .get (
236242 f"{ self .base_urls .api_base_url } /analysis/engine" ,
237- headers = { "Accept" : "application/octet-stream" } ,
243+ headers = ACCEPT_OCTET_STREAM ,
238244 auth = self .auth ,
239245 )
240246 self .__download_file (res , handle )
@@ -247,7 +253,7 @@ def get_analysis_jres(self, os: OsStr, arch: ArchStr) -> list[JRE]:
247253 res = requests .get (
248254 f"{ self .base_urls .api_base_url } /analysis/jres" ,
249255 auth = self .auth ,
250- headers = { "Accept" : "application/json" } ,
256+ headers = ACCEPT_JSON ,
251257 params = params ,
252258 )
253259 res .raise_for_status ()
@@ -265,13 +271,27 @@ def download_analysis_jre(self, id: str, handle: typing.BinaryIO) -> None:
265271 try :
266272 res = requests .get (
267273 f"{ self .base_urls .api_base_url } /analysis/jres/{ id } " ,
268- headers = { "Accept" : "application/octet-stream" } ,
274+ headers = ACCEPT_OCTET_STREAM ,
269275 auth = self .auth ,
270276 )
271277 self .__download_file (res , handle )
272278 except requests .RequestException as e :
273279 self .__raise_exception (e )
274280
281+ def download_file_from_url (self , url : str , handle : typing .BinaryIO ) -> None :
282+ """
283+ This method can raise a SonarQubeApiException if the server doesn't respond successfully.
284+ Alternative, if the file IO fails, an IOError or OSError can be raised.
285+ """
286+ try :
287+ res = requests .get (
288+ url ,
289+ headers = ACCEPT_OCTET_STREAM ,
290+ )
291+ self .__download_file (res , handle )
292+ except requests .RequestException as e :
293+ self .__raise_exception (e )
294+
275295 def __download_file (self , res : requests .Response , handle : typing .BinaryIO ) -> None :
276296 res .raise_for_status ()
277297 for chunk in res .iter_content (chunk_size = 128 ):
0 commit comments