"""Module for jenkinsapi Fingerprint"""from__future__importannotationsimportreimportloggingfromtypingimportAnyimportrequestsfromjenkinsapi.jenkinsbaseimportJenkinsBasefromjenkinsapi.custom_exceptionsimportArtifactBrokenlog:logging.Logger=logging.getLogger(__name__)
[docs]classFingerprint(JenkinsBase):""" Represents a jenkins fingerprint on a single artifact file ?? """RE_MD5=re.compile("^([0-9a-z]{32})$")def__init__(self,baseurl:str,id_:str,jenkins_obj:"Jenkins")->None:self.jenkins_obj:"Jenkins"=jenkins_objassertself.RE_MD5.search(id_),("%s does not look like ""a valid id"%id_)url:str=f"{baseurl}/fingerprint/{id_}/"JenkinsBase.__init__(self,url,poll=False)self.id_:str=id_self.unknown:bool=False# Previously uninitialized in ctor
[docs]defvalid(self)->bool:""" Return True / False if valid. If returns True, self.unknown is set to either True or False, and can be checked if we have positive validity (fingerprint known at server) or negative validity (fingerprint not known at server, but not really an error). """try:self.poll()self.unknown=Falseexceptrequests.exceptions.HTTPErroraserr:# We can't really say anything about the validity of# fingerprints not found -- but the artifact can still# exist, so it is not possible to definitely say they are# valid or not.# The response object is of type: requests.models.Response# extract the status code from itresponse_obj:Any=err.responseifresponse_obj.status_code==404:logging.warning("MD5 cannot be checked if fingerprints are not enabled")self.unknown=TruereturnTruereturnFalsereturnTrue
[docs]defvalidate_for_build(self,filename:str,job:str,build:int)->bool:ifnotself.valid():log.info("Fingerprint is not known to jenkins.")returnFalseifself.unknown:# not request error, but unknown to jenkinsreturnTrueifself._data["original"]isnotNone:ifself._data["original"]["name"]==job:ifself._data["original"]["number"]==build:returnTrueifself._data["fileName"]!=filename:log.info(msg="Filename from jenkins (%s) did not match provided (%s)"%(self._data["fileName"],filename))returnFalseforusage_iteminself._data["usage"]:ifusage_item["name"]==job:forrange_inusage_item["ranges"]["ranges"]:ifrange_["start"]<=build<=range_["end"]:msg=("This artifact was generated by %s ""between build %i and %i"%(job,range_["start"],range_["end"],))log.info(msg=msg)returnTruereturnFalse
[docs]defvalidate(self)->bool:try:assertself.valid()exceptAssertionErrorasae:raiseArtifactBroken("Artifact %s seems to be broken, check %s"%(self.id_,self.baseurl))fromaeexceptrequests.exceptions.HTTPError:raiseArtifactBroken("Unable to validate artifact id %s using %s"%(self.id_,self.baseurl))returnTrue
[docs]defget_info(self):""" Returns a tuple of build-name, build# and artifact filename for a good build. """self.poll()return(self._data["original"]["name"],self._data["original"]["number"],self._data["fileName"],)