class Leaper(ReviewBot.ReviewBot): def __init__(self, *args, **kwargs): ReviewBot.ReviewBot.__init__(self, *args, **kwargs) self.do_comments = True self.maintbot = MaintenanceChecker(*args, **kwargs) # for FactorySourceChecker self.factory = FactorySourceChecker(*args, **kwargs) self.needs_reviewteam = False self.pending_factory_submission = False self.source_in_factory = None self.needs_release_manager = False self.release_manager_group = 'leap-reviewers' self.must_approve_version_updates = False self.must_approve_maintenance_updates = False self.needs_check_source = False self.check_source_group = None self.automatic_submission = False # project => package list self.packages = {} def prepare_review(self): # update lookup information on every run if self.ibs: self.factory.parse_lookup('SUSE:SLE-12-SP3:GA') self.lookup_sp3 = self.factory.lookup.copy() return self.factory.parse_lookup('openSUSE:Leap:42.3') self.factory.parse_lookup('openSUSE:Leap:42.3:NonFree') self.lookup_423 = self.factory.lookup.copy() self.factory.reset_lookup() self.factory.parse_lookup('openSUSE:Leap:42.2:Update') self.factory.parse_lookup('openSUSE:Leap:42.2:NonFree:Update') self.lookup_422 = self.factory.lookup.copy() self.factory.reset_lookup() self.factory.parse_lookup('openSUSE:Leap:42.1:Update') self.lookup_421 = self.factory.lookup.copy() self.factory.reset_lookup() def get_source_packages(self, project, expand=False): """Return the list of packages in a project.""" query = {'expand': 1} if expand else {} root = ET.parse(osc.core.http_GET(osc.core.makeurl(self.apiurl,['source', project], query=query))).getroot() packages = [i.get('name') for i in root.findall('entry')] return packages def is_package_in_project(self, project, package): if not project in self.packages: self.packages[project] = self.get_source_packages(project) return True if package in self.packages[project] else False def rdiff_link(self, src_project, src_package, src_rev, target_project, target_package = None): if target_package is None: target_package = src_package return '[%(target_project)s/%(target_package)s](/package/rdiff/%(src_project)s/%(src_package)s?opackage=%(target_package)s&oproject=%(target_project)s&rev=%(src_rev)s)'%{ 'src_project': src_project, 'src_package': src_package, 'src_rev': src_rev, 'target_project': target_project, 'target_package': target_package, } def check_source_submission(self, src_project, src_package, src_rev, target_project, target_package): super(Leaper, self).check_source_submission(src_project, src_package, src_rev, target_project, target_package) src_srcinfo = self.get_sourceinfo(src_project, src_package, src_rev) package = target_package origin = None if src_srcinfo is None: # source package does not exist? # handle here to avoid crashing on the next line self.logger.warn("Could not get source info for %s/%s@%s" % (src_project, src_package, src_rev)) return False if self.ibs and target_project.startswith('SUSE:SLE'): if package in self.lookup_sp3: origin = self.lookup_sp3[package] origin_same = True if origin: origin_same = True if origin == 'FORK' else src_project.startswith(origin) self.logger.info("expected origin is '%s' (%s)", origin, "unchanged" if origin_same else "changed") prj = 'openSUSE.org:openSUSE:Factory' # True or None (open request) are acceptable for SLE. self.source_in_factory = self._check_factory(package, src_srcinfo, prj) if self.source_in_factory is None: self.pending_factory_submission = True if self.source_in_factory is not False: return self.source_in_factory # got false. could mean package doesn't exist or no match if self.is_package_in_project(prj, package): self.logger.info('different sources in {}'.format(self.rdiff_link(src_project, src_package, src_rev, prj, package))) prj = 'openSUSE.org:openSUSE:Leap:42.2' if self.is_package_in_project(prj, package): if self._check_factory(package, src_srcinfo, prj) is True: self.logger.info('found source match in {}'.format(prj)) else: self.logger.info('different sources in {}'.format(self.rdiff_link(src_project, src_package, src_rev, prj, package))) devel_project, devel_package = self.get_devel_project('openSUSE.org:openSUSE:Factory', package) if devel_project is not None: # specifying devel package is optional if devel_package is None: devel_package = package if self.is_package_in_project(devel_project, devel_package): if self.factory._check_project(devel_project, devel_package, src_srcinfo.verifymd5) == True: self.logger.info('matching sources in {}/{}'.format(devel_project, devel_package)) return True else: self.logger.info('different sources in {}'.format(self.rdiff_link(src_project, src_package, src_rev, devel_project, devel_package))) else: self.logger.info('no devel project found for {}/{}'.format('openSUSE.org:openSUSE:Factory', package)) self.logger.info('no matching sources in Factory, Leap:42.2, nor devel project') return origin_same if package in self.lookup_423: origin = self.lookup_423[package] is_fine_if_factory = False not_in_factory_okish = False if origin: origin_same = src_project.startswith(origin) self.logger.info("expected origin is '%s' (%s)", origin, "unchanged" if origin_same else "changed") if origin.startswith('Devel;'): (dummy, origin, dummy) = origin.split(';') if origin != src_project: self.logger.debug("not submitted from devel project") return False is_fine_if_factory = True not_in_factory_okish = True if self.must_approve_version_updates: self.needs_release_manager = True # fall through to check history and requests elif origin.startswith('openSUSE:Factory'): # A large number of requests are created by hand that leaper # would have created via update_crawler.py. This applies to # other origins, but primary looking to let Factory submitters # know that there is no need to make manual submissions to both. # Since it has a lookup entry it is not a new package. self.automatic_submission = True if self.must_approve_version_updates: self.needs_release_manager = True if origin == src_project: self.source_in_factory = True return True is_fine_if_factory = True # fall through to check history and requests elif origin == 'FORK': is_fine_if_factory = True not_in_factory_okish = True self.needs_release_manager = True self.needs_check_source = True # fall through to check history and requests elif origin.startswith('openSUSE:Leap:42.2'): if self.must_approve_maintenance_updates: self.needs_release_manager = True # submitted from :Update if origin_same: self.logger.debug("submission from 42.2 ok") return True # switching to sle package might make sense if src_project.startswith('SUSE:SLE-12'): self.needs_release_manager = True return True # submitted from elsewhere but is in :Update else: good = self.factory._check_project('openSUSE:Leap:42.2:Update', target_package, src_srcinfo.verifymd5) if good: self.logger.info("submission found in 42.2") return good # check release requests too good = self.factory._check_requests('openSUSE:Leap:42.2:Update', target_package, src_srcinfo.verifymd5) if good or good == None: self.logger.debug("found request") return good # let's see where it came from before if package in self.lookup_422: oldorigin = self.lookup_422[package] self.logger.debug("oldorigin {}".format(oldorigin)) # Factory. So it's ok to keep upgrading it to Factory # TODO: whitelist packages where this is ok and block others? if oldorigin.startswith('openSUSE:Factory'): self.logger.info("Package was from Factory in 42.2") # check if an attempt to switch to SLE package is made for sp in ('SP2:GA', 'SP2:Update', 'SP3:GA'): good = self.factory._check_project('SUSE:SLE-12-{}'.format(sp), target_package, src_srcinfo.verifymd5) if good: self.logger.info("request sources come from SLE") self.needs_release_manager = True return good # the release manager needs to review attempts to upgrade to Factory is_fine_if_factory = True self.needs_release_manager = True elif origin.startswith('SUSE:SLE-12'): if self.must_approve_maintenance_updates: self.needs_release_manager = True for v in ('42.3', '42.2'): prj = 'openSUSE:Leap:{}:SLE-workarounds'.format(v) if self.is_package_in_project( prj, target_package): self.logger.info("found package in %s", prj) if not self.factory._check_project(prj, target_package, src_srcinfo.verifymd5): self.logger.info("sources in %s are NOT identical", prj) self.needs_release_manager = True # submitted from :Update if origin == src_project: self.logger.debug("submission origin ok") return True elif origin.endswith(':GA') \ and src_project == origin[:-2]+'Update': self.logger.debug("sle update submission") return True # check if submitted from higher SP priolist = ['SUSE:SLE-12:', 'SUSE:SLE-12-SP1:', 'SUSE:SLE-12-SP2:', 'SUSE:SLE-12-SP3:'] for i in range(len(priolist)-1): if origin.startswith(priolist[i]): for prj in priolist[i+1:]: if src_project.startswith(prj): self.logger.info("submission from higher service pack %s:* ok", prj) return True self.needs_release_manager = True # the release manager needs to review attempts to upgrade to Factory is_fine_if_factory = True else: self.logger.error("unhandled origin %s", origin) return False else: # no origin # submission from SLE is ok if src_project.startswith('SUSE:SLE-12'): return True is_fine_if_factory = True self.needs_release_manager = True # we came here because none of the above checks find it good, so # let's see if the package is in Factory at least is_in_factory = self._check_factory(target_package, src_srcinfo) if is_in_factory: self.source_in_factory = True self.needs_reviewteam = False elif is_in_factory is None: self.pending_factory_submission = True self.needs_reviewteam = False else: if src_project.startswith('SUSE:SLE-12') \ or src_project.startswith('openSUSE:Leap:42.'): self.needs_reviewteam = False else: self.needs_reviewteam = True self.source_in_factory = False if is_fine_if_factory: if self.source_in_factory: return True elif self.pending_factory_submission: return None elif not_in_factory_okish: self.needs_reviewteam = True return True return False def _check_factory(self, target_package, src_srcinfo, target_project='openSUSE:Factory'): good = self.factory._check_project(target_project, target_package, src_srcinfo.verifymd5) if good: return good good = self.factory._check_requests(target_project, target_package, src_srcinfo.verifymd5) if good or good == None: self.logger.debug("found request to Factory") return good target_project_nonfree = '{}:NonFree'.format(target_project) good = self.factory._check_project(target_project_nonfree, target_package, src_srcinfo.verifymd5) if good: return good good = self.factory._check_requests(target_project_nonfree, target_package, src_srcinfo.verifymd5) if good or good == None: self.logger.debug('found request to {}'.format(target_project_nonfree)) return good return False def _check_project_and_request(self, project, target_package, src_srcinfo): good = self.factory._check_project(project, target_package, src_srcinfo.verifymd5) if good: return good good = self.factory._check_requests(project, target_package, src_srcinfo.verifymd5) if good or good == None: return good return False def check_one_request(self, req): self.review_messages = self.DEFAULT_REVIEW_MESSAGES.copy() self.needs_reviewteam = False self.needs_release_manager = False self.pending_factory_submission = False self.source_in_factory = None self.comment_handler_add() self.packages = {} if len(req.actions) != 1: msg = "only one action per request please" self.review_messages['declined'] = msg return False request_ok = ReviewBot.ReviewBot.check_one_request(self, req) if not self.ibs: has_correct_maintainer = self.maintbot.check_one_request(req) self.logger.debug("has_correct_maintainer: %s", has_correct_maintainer) self.logger.debug("review result: %s", request_ok) if self.pending_factory_submission: self.logger.info("submission is waiting for a Factory request to complete") creator = req.get_creator() bot_name = self.bot_name.lower() if self.automatic_submission and creator != bot_name: self.logger.info('@{}: this request would have been automatically created by {} after the Factory submission was accepted in order to eleviate the need to manually create requests for packages sourced from Factory'.format(creator, bot_name)) elif self.source_in_factory: self.logger.info("the submitted sources are in or accepted for Factory") elif self.source_in_factory == False: self.logger.info("the submitted sources are NOT in Factory") if request_ok == False: self.logger.info("NOTE: if you think the automated review was wrong here, please talk to the release team before reopening the request") elif self.needs_release_manager: self.logger.info("request needs review by release management") if self.do_comments: result = None if request_ok is None: state = 'seen' elif request_ok: state = 'done' result = 'accepted' else: state = 'done' result = 'declined' # Since leaper calls other bots (like maintbot) comments may # sometimes contain identical lines (like for unhandled requests). self.comment_handler_lines_deduplicate() self.comment_write(state, result) if self.needs_release_manager: add_review = True for r in req.reviews: if r.by_group == self.release_manager_group and (r.state == 'new' or r.state == 'accepted'): add_review = False self.logger.debug("%s already is a reviewer", self.release_manager_group) break if add_review: if self.add_review(req, by_group = self.release_manager_group) != True: self.review_messages['declined'] += '\nadding %s failed' % self.release_manager_group return False if self.needs_reviewteam: add_review = True self.logger.info("%s needs review by opensuse-review-team"%req.reqid) for r in req.reviews: if r.by_group == 'opensuse-review-team': add_review = False self.logger.debug("opensuse-review-team already is a reviewer") break if add_review: if self.add_review(req, by_group = "opensuse-review-team") != True: self.review_messages['declined'] += '\nadding opensuse-review-team failed' return False if self.needs_check_source and self.check_source_group is not None: add_review = True self.logger.info("%s needs review by %s" % (req.reqid, self.check_source_group)) for r in req.reviews: if r.by_group == self.check_source_group: add_review = False self.logger.debug("%s already is a reviewer", self.check_source_group) break if add_review: if self.add_review(req, by_group = self.check_source_group) != True: self.review_messages['declined'] += '\nadding %s failed' % self.check_source_group return False return request_ok def check_action__default(self, req, a): super(Leaper, self).check_action__default(req, a) self.needs_release_manager = True return True
class Leaper(ReviewBot.ReviewBot): def __init__(self, *args, **kwargs): ReviewBot.ReviewBot.__init__(self, *args, **kwargs) # ReviewBot options. self.only_one_action = True self.request_default_return = True self.comment_handler = True self.do_comments = True self.maintbot = MaintenanceChecker(*args, **kwargs) # for FactorySourceChecker self.factory = FactorySourceChecker(*args, **kwargs) self.needs_legal_review = False self.needs_reviewteam = False self.pending_factory_submission = False self.source_in_factory = None self.needs_release_manager = False self.release_manager_group = None self.review_team_group = None self.legal_review_group = None self.must_approve_version_updates = False self.must_approve_maintenance_updates = False self.needs_check_source = False self.check_source_group = None self.automatic_submission = False # project => package list self.packages = {} def prepare_review(self): # update lookup information on every run if self.ibs: self.factory.parse_lookup('SUSE:SLE-15:GA') self.lookup_sle15 = self.factory.lookup.copy() return self.factory.parse_lookup('openSUSE:Leap:15.0') self.factory.parse_lookup('openSUSE:Leap:15.0:NonFree') self.lookup_150 = self.factory.lookup.copy() def get_source_packages(self, project, expand=False): """Return the list of packages in a project.""" query = {'expand': 1} if expand else {} try: root = ET.parse( osc.core.http_GET( osc.core.makeurl(self.apiurl, ['source', project], query=query))).getroot() packages = [i.get('name') for i in root.findall('entry')] except urllib2.HTTPError as e: # in case the project doesn't exist yet (like sle update) if e.code != 404: raise e packages = [] return packages def is_package_in_project(self, project, package): if not project in self.packages: self.packages[project] = self.get_source_packages(project) return True if package in self.packages[project] else False def rdiff_link(self, src_project, src_package, src_rev, target_project, target_package=None): if target_package is None: target_package = src_package return '[%(target_project)s/%(target_package)s](/package/rdiff/%(src_project)s/%(src_package)s?opackage=%(target_package)s&oproject=%(target_project)s&rev=%(src_rev)s)' % { 'src_project': src_project, 'src_package': src_package, 'src_rev': src_rev, 'target_project': target_project, 'target_package': target_package, } def _check_same_origin(self, origin, project): if origin == 'FORK': return True if origin.startswith('Devel;'): (dummy, origin, dummy) = origin.split(';') return project.startswith(origin) def check_source_submission(self, src_project, src_package, src_rev, target_project, target_package): super(Leaper, self).check_source_submission(src_project, src_package, src_rev, target_project, target_package) self.automatic_submission = False if src_project == target_project and src_package == target_package: self.logger.info('self submission detected') self.needs_release_manager = True return True src_srcinfo = self.get_sourceinfo(src_project, src_package, src_rev) package = target_package origin = None if src_srcinfo is None: # source package does not exist? # handle here to avoid crashing on the next line self.logger.warn("Could not get source info for %s/%s@%s" % (src_project, src_package, src_rev)) return False if self.ibs and target_project.startswith('SUSE:SLE'): if package in self.lookup_sle15: origin = self.lookup_sle15[package] origin_same = True if origin: origin_same = self._check_same_origin(origin, src_project) self.logger.info("expected origin is '%s' (%s)", origin, "unchanged" if origin_same else "changed") prj = 'openSUSE.org:openSUSE:Factory' # True or None (open request) are acceptable for SLE. self.source_in_factory = self._check_factory( package, src_srcinfo, prj) if self.source_in_factory is None: self.pending_factory_submission = True if self.source_in_factory is not False: return self.source_in_factory # got false. could mean package doesn't exist or no match if self.is_package_in_project(prj, package): self.logger.info('different sources in {}'.format( self.rdiff_link(src_project, src_package, src_rev, prj, package))) prj = 'openSUSE.org:openSUSE:Leap:15.0' # TODO Ugly save for SLE-15-SP1. if False and self.is_package_in_project(prj, package): if self._check_factory(package, src_srcinfo, prj) is True: self.logger.info('found source match in {}'.format(prj)) else: self.logger.info('different sources in {}'.format( self.rdiff_link(src_project, src_package, src_rev, prj, package))) devel_project, devel_package = devel_project_get( self.apiurl, 'openSUSE.org:openSUSE:Factory', package) if devel_project is not None: # specifying devel package is optional if devel_package is None: devel_package = package if self.is_package_in_project(devel_project, devel_package): if self.factory._check_project( devel_project, devel_package, src_srcinfo.verifymd5) == True: self.logger.info('matching sources in {}/{}'.format( devel_project, devel_package)) return True else: self.logger.info('different sources in {}'.format( self.rdiff_link(src_project, src_package, src_rev, devel_project, devel_package))) else: self.logger.info('no devel project found for {}/{}'.format( 'openSUSE.org:openSUSE:Factory', package)) #self.logger.info('no matching sources in Factory, Leap:15.0, nor devel project') self.logger.info( 'no matching sources in Factory, nor devel project') if origin_same is False: # Rather than decline, leave review open in-case of change and # ask release manager for input via override comment. self.logger.info( 'Comment `(at){} override accept` to force accept.'.format( self.review_user)) self.needs_release_manager = True return None return origin_same if package in self.lookup_150: origin = self.lookup_150[package] # obviously if src_project in ('openSUSE:Factory', 'openSUSE:Factory:NonFree'): self.source_in_factory = True is_fine_if_factory = False not_in_factory_okish = False if origin: origin_same = self._check_same_origin(origin, src_project) self.logger.info("expected origin is '%s' (%s)", origin, "unchanged" if origin_same else "changed") if origin.startswith('Devel;'): if origin_same == False: self.logger.debug("not submitted from devel project") return False is_fine_if_factory = True not_in_factory_okish = True if self.must_approve_version_updates: self.needs_release_manager = True # fall through to check history and requests elif origin.startswith('openSUSE:Factory'): # A large number of requests are created by hand that leaper # would have created via update_crawler.py. This applies to # other origins, but primary looking to let Factory submitters # know that there is no need to make manual submissions to both. # Since it has a lookup entry it is not a new package. self.automatic_submission = False if self.must_approve_version_updates: self.needs_release_manager = True if origin == src_project: self.source_in_factory = True # no need to approve submissions from Factory if # the lookup file points to Factory. Just causes # spam for many maintainers #1393 self.do_check_maintainer_review = False is_fine_if_factory = True # fall through to check history and requests elif origin == 'FORK': is_fine_if_factory = True if not src_project.startswith('SUSE:SLE-'): not_in_factory_okish = True self.needs_check_source = True self.needs_release_manager = True # fall through to check history and requests # TODO Ugly save for 15.1 (n-1). elif False and origin.startswith('openSUSE:Leap:15.0'): if self.must_approve_maintenance_updates: self.needs_release_manager = True # submitted from :Update if origin_same: self.logger.debug("submission from 15.0 ok") return True # switching to sle package might make sense if src_project.startswith('SUSE:SLE-15'): self.needs_release_manager = True return True # submitted from elsewhere but is in :Update else: good = self.factory._check_project( 'openSUSE:Leap:15.0:Update', target_package, src_srcinfo.verifymd5) if good: self.logger.info("submission found in 15.0") return good # check release requests too good = self.factory._check_requests( 'openSUSE:Leap:15.0:Update', target_package, src_srcinfo.verifymd5) if good or good == None: self.logger.debug("found request") return good # let's see where it came from before if package in self.lookup_150: oldorigin = self.lookup_150[package] self.logger.debug("oldorigin {}".format(oldorigin)) # Factory. So it's ok to keep upgrading it to Factory # TODO: whitelist packages where this is ok and block others? self.logger.info("Package was from %s in 15.0", oldorigin) if oldorigin.startswith('openSUSE:Factory'): # check if an attempt to switch to SLE package is made for sp in ('SP1:GA', 'SP1:Update'): good = self.factory._check_project( 'SUSE:SLE-15-{}'.format(sp), target_package, src_srcinfo.verifymd5) if good: self.logger.info( "request sources come from SLE") self.needs_release_manager = True return good # TODO Ugly save for 15.2 (n-2). elif False and oldorigin.startswith('openSUSE:Leap:15.0'): o = self.lookup_150[package] self.logger.info("Package was from %s in 15.0", o) # the release manager needs to review attempts to upgrade to Factory is_fine_if_factory = True self.needs_release_manager = True elif origin.startswith('SUSE:SLE-15'): if self.must_approve_maintenance_updates: self.needs_release_manager = True for v in ('15.0', ): prj = 'openSUSE:Leap:{}:SLE-workarounds'.format(v) if self.is_package_in_project(prj, target_package): self.logger.info("found package in %s", prj) if not self.factory._check_project( prj, target_package, src_srcinfo.verifymd5): self.logger.info( "sources in %s are [NOT identical](%s)", prj, self.rdiff_link(src_project, src_package, src_rev, prj, package)) self.needs_release_manager = True # submitted from :Update if origin == src_project: self.logger.debug("submission origin ok") return True elif origin.endswith(':GA') \ and src_project == origin[:-2]+'Update': self.logger.debug("sle update submission") return True # check if submitted from higher SP priolist = [ 'SUSE:SLE-15:', 'SUSE:SLE-15-SP1:', 'SUSE:SLE-15-SP2:', 'SUSE:SLE-15-SP3:' ] for i in range(len(priolist) - 1): if origin.startswith(priolist[i]): for prj in priolist[i + 1:]: if src_project.startswith(prj): self.logger.info( "submission from higher service pack %s:* ok", prj) return True in_sle_origin = self._check_factory(target_package, src_srcinfo, origin) if in_sle_origin: self.logger.info( 'parallel submission, also in {}'.format(origin)) return True self.needs_release_manager = True # the release manager needs to review attempts to upgrade to Factory is_fine_if_factory = True else: self.logger.error("unhandled origin %s", origin) return False else: # no origin # submission from SLE is ok if src_project.startswith('SUSE:SLE-15'): self.do_check_maintainer_review = False return True # new package submitted from Factory. Check if it was in # 42.3 before and skip maintainer review if so. subprj = src_project[len('openSUSE:Factory'):] if self.source_in_factory and target_project.startswith('openSUSE:Leap:15.0') \ and self.is_package_in_project('openSUSE:Leap:42.3'+subprj, package): self.logger.info('package was in 42.3') self.do_check_maintainer_review = False return True is_fine_if_factory = True self.needs_release_manager = True if origin is None or not origin.startswith('SUSE:SLE-'): for p in (':Update', ':GA'): prj = 'SUSE:SLE-15' + p if self.is_package_in_project(prj, package): self.logger.info('Package is in {}'.format( self.rdiff_link(src_project, src_package, src_rev, prj, package))) break is_in_factory = self.source_in_factory # we came here because none of the above checks find it good, so # let's see if the package is in Factory at least if is_in_factory is None: is_in_factory = self._check_factory(package, src_srcinfo) if is_in_factory: self.source_in_factory = True self.needs_reviewteam = False self.needs_legal_review = False elif is_in_factory is None: self.pending_factory_submission = True self.needs_reviewteam = False self.needs_legal_review = False else: if src_project.startswith('SUSE:SLE-15') \ or src_project.startswith('openSUSE:Leap:15.'): self.needs_reviewteam = False self.needs_legal_review = False else: self.needs_reviewteam = True self.needs_legal_review = True self.source_in_factory = False if is_fine_if_factory: if self.source_in_factory: return True elif self.pending_factory_submission: return None elif not_in_factory_okish: self.needs_reviewteam = True self.needs_legal_review = True return True if self.override_allow: # Rather than decline, leave review open and ask release # manager for input via override comment. self.logger.info( 'Comment `(at){} override accept` to force accept.'.format( self.review_user)) self.needs_release_manager = True return None return False def _check_factory(self, target_package, src_srcinfo, target_project='openSUSE:Factory'): for subprj in ('', ':NonFree', ':Live'): prj = ''.join((target_project, subprj)) good = self.factory._check_project(prj, target_package, src_srcinfo.verifymd5) if good: return good good = self.factory._check_requests(prj, target_package, src_srcinfo.verifymd5) if good or good == None: self.logger.debug("found request to %s", prj) return good return False def _check_project_and_request(self, project, target_package, src_srcinfo): good = self.factory._check_project(project, target_package, src_srcinfo.verifymd5) if good: return good good = self.factory._check_requests(project, target_package, src_srcinfo.verifymd5) if good or good == None: return good return False def check_one_request(self, req): api = self.staging_api(req.actions[0].tgt_project) config = self.staging_config[api.project] self.needs_legal_review = False self.needs_reviewteam = False self.needs_release_manager = False self.pending_factory_submission = False self.source_in_factory = None self.do_check_maintainer_review = not self.ibs self.packages = {} request_ok = ReviewBot.ReviewBot.check_one_request(self, req) if self.do_check_maintainer_review: has_correct_maintainer = self.maintbot.check_one_request(req) self.logger.debug("has_correct_maintainer: %s", has_correct_maintainer) self.logger.debug("review result: %s", request_ok) if self.pending_factory_submission: self.logger.info( "submission is waiting for a Factory request to complete") creator = req.get_creator() bot_name = self.bot_name.lower() if self.automatic_submission and creator != bot_name: self.logger.info( '@{}: this request would have been automatically created by {} after the Factory submission was accepted in order to eleviate the need to manually create requests for packages sourced from Factory' .format(creator, bot_name)) elif self.source_in_factory: self.logger.info( "the submitted sources are in or accepted for Factory") elif self.source_in_factory == False: self.logger.info("the submitted sources are NOT in Factory") if request_ok == False: self.logger.info( "NOTE: if you think the automated review was wrong here, please talk to the release team before reopening the request" ) if self.do_comments: result = None if request_ok is None: state = 'seen' elif request_ok: state = 'done' result = 'accepted' else: state = 'done' result = 'declined' # Since leaper calls other bots (like maintbot) comments may # sometimes contain identical lines (like for unhandled requests). self.comment_handler_lines_deduplicate() self.comment_write(state, result) add_review_groups = [] if self.needs_release_manager: add_review_groups.append(self.release_manager_group or config.get(self.override_group_key)) if self.needs_reviewteam: add_review_groups.append(self.review_team_group or config.get('review-team')) if self.needs_legal_review: add_review_groups.append(self.legal_review_group or config.get('legal-review-group')) if self.needs_check_source and self.check_source_group is not None: add_review_groups.append(self.check_source_group) for group in add_review_groups: if group is None: continue self.logger.info( "{0} needs review by [{1}](/group/show/{1})".format( req.reqid, group)) self.add_review(req, by_group=group) return request_ok def check_action__default(self, req, a): self.needs_release_manager = True if self.ibs: self.do_check_maintainer_review = False return super(Leaper, self).check_action__default(req, a)
class Leaper(ReviewBot.ReviewBot): def __init__(self, *args, **kwargs): ReviewBot.ReviewBot.__init__(self, *args, **kwargs) self.maintbot = MaintenanceChecker(*args, **kwargs) # for FactorySourceChecker self.factory = FactorySourceChecker(*args, **kwargs) self.needs_reviewteam = False self.pending_factory_submission = False self.source_in_factory = False def prepare_review(self): # update lookup information on every run self.factory.parse_lookup('openSUSE:Leap:42.2') self.factory.parse_lookup('openSUSE:Leap:42.2:NonFree') self.lookup_422 = self.factory.lookup.copy() self.factory.lookup = {} self.factory.parse_lookup('openSUSE:Leap:42.1:Update') self.lookup_421 = self.factory.lookup.copy() self.factory.lookup = {} def check_source_submission(self, src_project, src_package, src_rev, target_project, target_package): self.logger.info("%s/%s@%s -> %s/%s" % (src_project, src_package, src_rev, target_project, target_package)) src_srcinfo = self.get_sourceinfo(src_project, src_package, src_rev) package = target_package if src_srcinfo is None: # source package does not exist? # handle here to avoid crashing on the next line self.logger.warn("Could not get source info for %s/%s@%s" % (src_project, src_package, src_rev)) return False origin = None if package in self.lookup_422: origin = self.lookup_422[package] if origin: self.logger.debug("origin {}".format(origin)) if origin.startswith('Devel;'): self.needs_reviewteam = True (dummy, origin, dummy) = origin.split(';') if origin == src_project: self.logger.debug("exact match") return True elif origin.startswith('openSUSE:Factory'): return self._check_factory(target_package, src_srcinfo) elif origin.startswith('openSUSE:Leap:42.1'): # submitted from :Update if src_project.startswith(origin): self.logger.debug("match 42.1") return True # submitted from elsewhere but is in :Update else: good = self.factory._check_project( 'openSUSE:Leap:42.1:Update', target_package, src_srcinfo.verifymd5) if good: self.logger.info("submission found in 42.1") return good # check release requests too good = self.factory._check_requests( 'openSUSE:Leap:42.1:Update', target_package, src_srcinfo.verifymd5) if good or good == None: self.logger.debug("found request") return good # let's see where it came from before if package in self.lookup_421: oldorigin = self.lookup_421[package] self.logger.debug("oldorigin {}".format(oldorigin)) # Factory. So it's ok to keep upgrading it to Factory # TODO: whitelist packages where this is ok and block others? if oldorigin.startswith('openSUSE:Factory'): if src_project == oldorigin: self.logger.debug( "Upgrade to Factory again. Submitted from Factory" ) return True good = self._check_factory(target_package, src_srcinfo) if good or good == None: self.logger.debug( "Upgrade to Factory again. It's in Factory") return good # or maybe in SP2? good = self.factory._check_project( 'SUSE:SLE-12-SP2:GA', target_package, src_srcinfo.verifymd5) if good: self.logger.debug("hope it's ok to change to SP2") return good # else other project or FORK, fall through elif origin.startswith('SUSE:SLE-12'): # submitted from :Update if src_project.startswith(origin): self.logger.debug("match sle") return True # submitted from higher SP if origin.startswith('SUSE:SLE-12'): if src_project.startswith('SUSE:SLE-12-SP1') \ or src_project.startswith('SUSE:SLE-12-SP2'): self.logger.debug("higher service pack ok") return True # else other project or FORK, fall through # we came here because none of the above checks find it good, so # let's see if the package is in Factory at least is_in_factory = self._check_factory(target_package, src_srcinfo) if is_in_factory: self.source_in_factory = True elif is_in_factory is None: self.pending_factory_submission = True else: if not src_project.startswith('SUSE:SLE-12'): self.needs_reviewteam = True else: # no origin # SLE and Factory are ok if src_project.startswith('SUSE:SLE-12') \ or src_project.startswith('openSUSE:Factory'): return True # submitted from elsewhere, check it's in Factory good = self._check_factory(target_package, src_srcinfo) if good: self.source_in_factory = True return True elif good == None: self.pending_factory_submission = True return good # or maybe in SP2? good = self.factory._check_project('SUSE:SLE-12-SP2:GA', target_package, src_srcinfo.verifymd5) if good: return good return False def _check_factory(self, target_package, src_srcinfo): good = self.factory._check_project('openSUSE:Factory', target_package, src_srcinfo.verifymd5) if good: return good good = self.factory._check_requests('openSUSE:Factory', target_package, src_srcinfo.verifymd5) if good or good == None: self.logger.debug("found request to Factory") return good good = self.factory._check_project('openSUSE:Factory:NonFree', target_package, src_srcinfo.verifymd5) if good: return good good = self.factory._check_requests('openSUSE:Factory:NonFree', target_package, src_srcinfo.verifymd5) if good or good == None: self.logger.debug("found request to Factory:NonFree") return good return False def check_one_request(self, req): self.review_messages = self.DEFAULT_REVIEW_MESSAGES.copy() self.needs_reviewteam = False self.pending_factory_submission = False self.source_in_factory = False if len(req.actions) != 1: msg = "only one action per request please" self.review_messages['declined'] = msg return False # if the fallback reviewer created the request she probably # knows what she does :-) if self.fallback_user and req.get_creator() == self.fallback_user: self.logger.debug("skip fallback review") return True has_upstream_sources = ReviewBot.ReviewBot.check_one_request(self, req) has_correct_maintainer = self.maintbot.check_one_request(req) # not reviewed yet? if has_upstream_sources is None: return None self.logger.debug("upstream sources: {}, maintainer ok: {}".format( has_upstream_sources, has_correct_maintainer)) if self.needs_reviewteam: add_review = True self.logger.debug("%s needs review by opensuse-review-team" % req.reqid) for r in req.reviews: if r.by_group == 'opensuse-review-team': add_review = False self.logger.debug( "opensuse-review-team already is a reviewer") break if add_review: if self.add_review(req, by_group="opensuse-review-team") != True: self.review_messages[ 'declined'] += '\nadding opensuse-review-team failed' return False if has_upstream_sources != True or has_correct_maintainer != True: if has_upstream_sources != True: self.review_messages['declined'] += '\nOrigin project changed' pkg = req.actions[0].tgt_package if pkg in self.lookup_422: self.review_messages['declined'] += '(was {})'.format( self.lookup_422[pkg]) if self.source_in_factory: self.review_messages[ 'declined'] += '\nsource is in Factory' if self.pending_factory_submission: self.review_messages[ 'declined'] += '\na submission to Factory is pending' self.logger.debug( "origin changed but waiting for Factory submission to complete" ) # FXIME: we should add the human reviewer here # and leave a comment return None # shouldn't happen actually if has_correct_maintainer != True: self.review_messages['declined'] += '\nMaintainer check failed' return False return True def check_action__default(self, req, a): # decline all other requests for fallback reviewer self.logger.debug("auto decline request type %s" % a.type) return False
class Leaper(ReviewBot.ReviewBot): def __init__(self, *args, **kwargs): ReviewBot.ReviewBot.__init__(self, *args, **kwargs) self.maintbot = MaintenanceChecker(*args, **kwargs) # for FactorySourceChecker self.lookup_checker = FactorySourceChecker(*args, **kwargs) self.lookup_checker.parse_lookup('openSUSE:Leap:42.2') self.lookup_checker.parse_lookup('openSUSE:Leap:42.2:NonFree') self.factory = FactorySourceChecker(*args, **kwargs) # XXX: FactorySourceChecker should be able to handle that itself self.factory_nonfree = FactorySourceChecker(*args, **kwargs) self.factory_nonfree.factory = 'openSUSE:Factory:NonFree' def check_source_submission(self, src_project, src_package, src_rev, target_project, target_package): return self.lookup_checker.check_source_submission(src_project, src_package, src_rev, target_project, target_package) def check_one_request(self, req): self.review_messages = self.DEFAULT_REVIEW_MESSAGES.copy() if len(req.actions) != 1: msg = "only one action per request please" self.review_messages['declined'] = msg return False # if the fallback reviewer created the request she probably # knows what she does :-) if self.fallback_user and req.get_creator() == self.fallback_user: self.logger.debug("skip fallback review") return True has_upstream_sources = ReviewBot.ReviewBot.check_one_request(self, req) has_correct_maintainer = self.maintbot.check_one_request(req) # not reviewed yet? if has_upstream_sources is None: return None self.logger.debug("upstream sources: {}, maintainer ok: {}".format(has_upstream_sources, has_correct_maintainer)) if has_upstream_sources != True or has_correct_maintainer != True: if has_upstream_sources != True: self.review_messages['declined'] += '\nOrigin project changed' pkg = req.actions[0].tgt_package prj = self.lookup_checker._package_get_upstream_project(pkg) if prj: self.review_messages['declined'] += '(was {})'.format(prj) r = self.factory.check_one_request(req) if r == True: self.review_messages['declined'] += '\nsource is in Factory though' elif r == None: self.logger.info("waiting for review") return None else: r = self.factory_nonfree.check_one_request(req) if r == True: self.review_messages['declined'] += '\nsource is in Factory:NonFree though' elif r == None: self.logger.info("waiting for review") return None # shouldn't happen actually if has_correct_maintainer != True: self.review_messages['declined'] += '\nMaintainer check failed' return False return True
class Leaper(ReviewBot.ReviewBot): def __init__(self, *args, **kwargs): ReviewBot.ReviewBot.__init__(self, *args, **kwargs) self.maintbot = MaintenanceChecker(*args, **kwargs) # for FactorySourceChecker self.factory = FactorySourceChecker(*args, **kwargs) self.needs_reviewteam = False self.pending_factory_submission = False self.source_in_factory = False def prepare_review(self): # update lookup information on every run self.factory.parse_lookup('openSUSE:Leap:42.2') self.factory.parse_lookup('openSUSE:Leap:42.2:NonFree') self.lookup_422 = self.factory.lookup.copy() self.factory.lookup = {} self.factory.parse_lookup('openSUSE:Leap:42.1:Update') self.lookup_421 = self.factory.lookup.copy() self.factory.lookup = {} def check_source_submission(self, src_project, src_package, src_rev, target_project, target_package): self.logger.info("%s/%s@%s -> %s/%s"%(src_project, src_package, src_rev, target_project, target_package)) src_srcinfo = self.get_sourceinfo(src_project, src_package, src_rev) package = target_package if src_srcinfo is None: # source package does not exist? # handle here to avoid crashing on the next line self.logger.warn("Could not get source info for %s/%s@%s" % (src_project, src_package, src_rev)) return False origin = None if package in self.lookup_422: origin = self.lookup_422[package] if origin: self.logger.debug("origin {}".format(origin)) if origin.startswith('Devel;'): self.needs_reviewteam = True (dummy, origin, dummy) = origin.split(';') if origin == src_project: self.logger.debug("exact match") return True elif origin.startswith('openSUSE:Factory'): return self._check_factory(target_package, src_srcinfo) elif origin.startswith('openSUSE:Leap:42.1'): # submitted from :Update if src_project.startswith(origin): self.logger.debug("match 42.1") return True # submitted from elsewhere but is in :Update else: good = self.factory._check_project('openSUSE:Leap:42.1:Update', target_package, src_srcinfo.verifymd5) if good: self.logger.info("submission found in 42.1") return good # check release requests too good = self.factory._check_requests('openSUSE:Leap:42.1:Update', target_package, src_srcinfo.verifymd5) if good or good == None: self.logger.debug("found request") return good # let's see where it came from before if package in self.lookup_421: oldorigin = self.lookup_421[package] self.logger.debug("oldorigin {}".format(oldorigin)) # Factory. So it's ok to keep upgrading it to Factory # TODO: whitelist packages where this is ok and block others? if oldorigin.startswith('openSUSE:Factory'): if src_project == oldorigin: self.logger.debug("Upgrade to Factory again. Submitted from Factory") return True good = self._check_factory(target_package, src_srcinfo) if good or good == None: self.logger.debug("Upgrade to Factory again. It's in Factory") return good # or maybe in SP2? good = self.factory._check_project('SUSE:SLE-12-SP2:GA', target_package, src_srcinfo.verifymd5) if good: self.logger.debug("hope it's ok to change to SP2") return good # else other project or FORK, fall through elif origin.startswith('SUSE:SLE-12'): # submitted from :Update if src_project.startswith(origin): self.logger.debug("match sle") return True # submitted from higher SP if origin.startswith('SUSE:SLE-12'): if src_project.startswith('SUSE:SLE-12-SP1') \ or src_project.startswith('SUSE:SLE-12-SP2'): self.logger.debug("higher service pack ok") return True # else other project or FORK, fall through # we came here because none of the above checks find it good, so # let's see if the package is in Factory at least is_in_factory = self._check_factory(target_package, src_srcinfo) if is_in_factory: self.source_in_factory = True elif is_in_factory is None: self.pending_factory_submission = True else: if not src_project.startswith('SUSE:SLE-12'): self.needs_reviewteam = True else: # no origin # SLE and Factory are ok if src_project.startswith('SUSE:SLE-12') \ or src_project.startswith('openSUSE:Factory'): return True # submitted from elsewhere, check it's in Factory good = self._check_factory(target_package, src_srcinfo) if good: self.source_in_factory = True return True elif good == None: self.pending_factory_submission = True return good # or maybe in SP2? good = self.factory._check_project('SUSE:SLE-12-SP2:GA', target_package, src_srcinfo.verifymd5) if good: return good return False def _check_factory(self, target_package, src_srcinfo): good = self.factory._check_project('openSUSE:Factory', target_package, src_srcinfo.verifymd5) if good: return good good = self.factory._check_requests('openSUSE:Factory', target_package, src_srcinfo.verifymd5) if good or good == None: self.logger.debug("found request to Factory") return good good = self.factory._check_project('openSUSE:Factory:NonFree', target_package, src_srcinfo.verifymd5) if good: return good good = self.factory._check_requests('openSUSE:Factory:NonFree', target_package, src_srcinfo.verifymd5) if good or good == None: self.logger.debug("found request to Factory:NonFree") return good return False def check_one_request(self, req): self.review_messages = self.DEFAULT_REVIEW_MESSAGES.copy() self.needs_reviewteam = False self.pending_factory_submission = False self.source_in_factory = False if len(req.actions) != 1: msg = "only one action per request please" self.review_messages['declined'] = msg return False # if the fallback reviewer created the request she probably # knows what she does :-) if self.fallback_user and req.get_creator() == self.fallback_user: self.logger.debug("skip fallback review") return True has_upstream_sources = ReviewBot.ReviewBot.check_one_request(self, req) has_correct_maintainer = self.maintbot.check_one_request(req) # not reviewed yet? if has_upstream_sources is None: return None self.logger.debug("upstream sources: {}, maintainer ok: {}".format(has_upstream_sources, has_correct_maintainer)) if self.needs_reviewteam: add_review = True self.logger.debug("%s needs review by opensuse-review-team"%req.reqid) for r in req.reviews: if r.by_group == 'opensuse-review-team': add_review = False self.logger.debug("opensuse-review-team already is a reviewer") break if add_review: if self.add_review(req, by_group = "opensuse-review-team") != True: self.review_messages['declined'] += '\nadding opensuse-review-team failed' return False if has_upstream_sources != True or has_correct_maintainer != True: if has_upstream_sources != True: self.review_messages['declined'] += '\nOrigin project changed' pkg = req.actions[0].tgt_package if pkg in self.lookup_422: self.review_messages['declined'] += '(was {})'.format(self.lookup_422[pkg]) if self.source_in_factory: self.review_messages['declined'] += '\nsource is in Factory' if self.pending_factory_submission: self.review_messages['declined'] += '\na submission to Factory is pending' self.logger.debug("origin changed but waiting for Factory submission to complete") # FXIME: we should add the human reviewer here # and leave a comment return None # shouldn't happen actually if has_correct_maintainer != True: self.review_messages['declined'] += '\nMaintainer check failed' return False return True def check_action__default(self, req, a): # decline all other requests for fallback reviewer self.logger.debug("auto decline request type %s"%a.type) return False
class Leaper(ReviewBot.ReviewBot): def __init__(self, *args, **kwargs): ReviewBot.ReviewBot.__init__(self, *args, **kwargs) self.do_comments = True self.commentapi = CommentAPI(self.apiurl) self.maintbot = MaintenanceChecker(*args, **kwargs) # for FactorySourceChecker self.factory = FactorySourceChecker(*args, **kwargs) self.needs_reviewteam = False self.pending_factory_submission = False self.source_in_factory = None self.needs_release_manager = False self.release_manager_group = 'leap-reviewers' self.must_approve_version_updates = False self.must_approve_maintenance_updates = False self.comment_marker_re = re.compile(r'<!-- leaper state=(?P<state>done|seen)(?: result=(?P<result>accepted|declined))? -->') self.comment_log = None self.commentlogger = LogToString(self, 'comment_log') self.logger.addFilter(self.commentlogger) def prepare_review(self): # update lookup information on every run self.factory.parse_lookup('openSUSE:Leap:42.2') self.factory.parse_lookup('openSUSE:Leap:42.2:NonFree') self.lookup_422 = self.factory.lookup.copy() self.factory.lookup = {} self.factory.parse_lookup('openSUSE:Leap:42.1:Update') self.lookup_421 = self.factory.lookup.copy() self.factory.lookup = {} def check_source_submission(self, src_project, src_package, src_rev, target_project, target_package): self.logger.info("%s/%s@%s -> %s/%s"%(src_project, src_package, src_rev, target_project, target_package)) src_srcinfo = self.get_sourceinfo(src_project, src_package, src_rev) package = target_package if src_srcinfo is None: # source package does not exist? # handle here to avoid crashing on the next line self.logger.warn("Could not get source info for %s/%s@%s" % (src_project, src_package, src_rev)) return False origin = None if package in self.lookup_422: origin = self.lookup_422[package] is_fine_if_factory = False not_in_factory_okish = False if origin: self.logger.info("expected origin is '%s'", origin) if origin.startswith('Devel;'): (dummy, origin, dummy) = origin.split(';') if origin != src_project: self.logger.debug("not submitted from devel project") return False is_fine_if_factory = True not_in_factory_okish = True if self.must_approve_version_updates: self.needs_release_manager = True # fall through to check history and requests elif origin.startswith('openSUSE:Factory'): if self.must_approve_version_updates: self.needs_release_manager = True if origin == src_project: self.source_in_factory = True return True is_fine_if_factory = True # fall through to check history and requests elif origin == 'FORK': is_fine_if_factory = True not_in_factory_okish = True self.needs_release_manager = True # fall through to check history and requests elif origin.startswith('openSUSE:Leap:42.1'): if self.must_approve_maintenance_updates: self.needs_release_manager = True # submitted from :Update if src_project.startswith(origin): self.logger.debug("submission from 42.1 ok") return True # submitted from elsewhere but is in :Update else: good = self.factory._check_project('openSUSE:Leap:42.1:Update', target_package, src_srcinfo.verifymd5) if good: self.logger.info("submission found in 42.1") return good # check release requests too good = self.factory._check_requests('openSUSE:Leap:42.1:Update', target_package, src_srcinfo.verifymd5) if good or good == None: self.logger.debug("found request") return good # let's see where it came from before if package in self.lookup_421: oldorigin = self.lookup_421[package] self.logger.debug("oldorigin {}".format(oldorigin)) # Factory. So it's ok to keep upgrading it to Factory # TODO: whitelist packages where this is ok and block others? if oldorigin.startswith('openSUSE:Factory'): self.logger.info("Package was from Factory in 42.1") # check if an attempt to switch to SLE package is made good = self.factory._check_project('SUSE:SLE-12-SP2:GA', target_package, src_srcinfo.verifymd5) if good: self.logger.info("request sources come from SLE") self.needs_release_manager = True return good # the release manager needs to review attempts to upgrade to Factory is_fine_if_factory = True self.needs_release_manager = True elif origin.startswith('SUSE:SLE-12'): if self.must_approve_maintenance_updates: self.needs_release_manager = True # submitted from :Update if origin == src_project: self.logger.debug("submission origin ok") return True elif origin.endswith(':GA') \ and src_project == origin[:-2]+'Update': self.logger.debug("sle update submission") return True # submitted from higher SP if origin.startswith('SUSE:SLE-12:'): if src_project.startswith('SUSE:SLE-12-SP1:') \ or src_project.startswith('SUSE:SLE-12-SP2:'): self.logger.info("submission from service pack ok") return True elif origin.startswith('SUSE:SLE-12-SP1:'): if src_project.startswith('SUSE:SLE-12-SP2:'): self.logger.info("submission from service pack ok") return True self.needs_release_manager = True good = self._check_project_and_request('openSUSE:Leap:42.2:SLE-workarounds', target_package, src_srcinfo) if good or good == None: self.logger.info("found sources in SLE-workarounds") return good # the release manager needs to review attempts to upgrade to Factory is_fine_if_factory = True else: self.logger.error("unhandled origin %s", origin) return False else: # no origin # submission from SLE is ok if src_project.startswith('SUSE:SLE-12'): return True is_fine_if_factory = True self.needs_release_manager = True # we came here because none of the above checks find it good, so # let's see if the package is in Factory at least is_in_factory = self._check_factory(target_package, src_srcinfo) if is_in_factory: self.source_in_factory = True self.needs_reviewteam = False elif is_in_factory is None: self.pending_factory_submission = True self.needs_reviewteam = False else: if src_project.startswith('SUSE:SLE-12') \ or src_project.startswith('openSUSE:Leap:42.'): self.needs_reviewteam = False else: self.needs_reviewteam = True self.source_in_factory = False if is_fine_if_factory: if self.source_in_factory: return True elif self.pending_factory_submission: return None elif not_in_factory_okish: self.needs_reviewteam = True return True return False def _check_factory(self, target_package, src_srcinfo): good = self.factory._check_project('openSUSE:Factory', target_package, src_srcinfo.verifymd5) if good: return good good = self.factory._check_requests('openSUSE:Factory', target_package, src_srcinfo.verifymd5) if good or good == None: self.logger.debug("found request to Factory") return good good = self.factory._check_project('openSUSE:Factory:NonFree', target_package, src_srcinfo.verifymd5) if good: return good good = self.factory._check_requests('openSUSE:Factory:NonFree', target_package, src_srcinfo.verifymd5) if good or good == None: self.logger.debug("found request to Factory:NonFree") return good return False def _check_project_and_request(self, project, target_package, src_srcinfo): good = self.factory._check_project(project, target_package, src_srcinfo.verifymd5) if good: return good good = self.factory._check_requests(project, target_package, src_srcinfo.verifymd5) if good or good == None: return good return False def check_one_request(self, req): self.review_messages = self.DEFAULT_REVIEW_MESSAGES.copy() self.needs_reviewteam = False self.needs_release_manager = False self.pending_factory_submission = False self.source_in_factory = None self.comment_log = [] if len(req.actions) != 1: msg = "only one action per request please" self.review_messages['declined'] = msg return False request_ok = ReviewBot.ReviewBot.check_one_request(self, req) has_correct_maintainer = self.maintbot.check_one_request(req) self.logger.debug("review result: %s", request_ok) self.logger.debug("has_correct_maintainer: %s", has_correct_maintainer) if self.pending_factory_submission: self.logger.info("submission is waiting for a Factory request to complete") elif self.source_in_factory: self.logger.info("the submitted sources are in or accepted for Factory") elif self.source_in_factory == False: self.logger.info("the submitted sources are NOT in Factory") if request_ok == False: self.logger.info("NOTE: if you think the automated review was wrong here, please talk to the release team before reopening the request") elif self.needs_release_manager: self.logger.info("request needs review by release management") if self.comment_log: result = None if request_ok is None: state = 'seen' elif request_ok: state = 'done' result = 'accepted' else: state = 'done' result = 'declined' self.add_comment(req, '\n\n'.join(self.comment_log), state) self.comment_log = None if self.needs_release_manager: add_review = True for r in req.reviews: if r.by_group == self.release_manager_group and (r.state == 'new' or r.state == 'accepted'): add_review = False self.logger.debug("%s already is a reviewer", self.release_manager_group) break if add_review: if self.add_review(req, by_group = self.release_manager_group) != True: self.review_messages['declined'] += '\nadding %s failed' % self.release_manager_group return False if self.needs_reviewteam: add_review = True self.logger.info("%s needs review by opensuse-review-team"%req.reqid) for r in req.reviews: if r.by_group == 'opensuse-review-team': add_review = False self.logger.debug("opensuse-review-team already is a reviewer") break if add_review: if self.add_review(req, by_group = "opensuse-review-team") != True: self.review_messages['declined'] += '\nadding opensuse-review-team failed' return False return request_ok def check_action__default(self, req, a): # decline all other requests for fallback reviewer self.logger.debug("auto decline request type %s"%a.type) return False # TODO: make generic, move to Reviewbot. Used by multiple bots def add_comment(self, req, msg, state, result=None): if not self.do_comments: return comment = "<!-- leaper state=%s%s -->\n" % (state, ' result=%s' % result if result else '') comment += "\n" + msg (comment_id, comment_state, comment_result, comment_text) = self.find_obs_request_comment(req, state) if comment_id is not None and state == comment_state: # count number of lines as aproximation to avoid spamming requests # for slight wording changes in the code if len(comment_text.split('\n')) == len(comment.split('\n')): self.logger.debug("not worth the update, previous comment %s is state %s", comment_id, comment_state) return self.logger.debug("adding comment to %s, state %s result %s", req.reqid, state, result) self.logger.debug("message: %s", msg) if not self.dryrun: if comment_id is not None: self.commentapi.delete(comment_id) self.commentapi.add_comment(request_id=req.reqid, comment=str(comment)) def find_obs_request_comment(self, req, state=None): """Return previous comments (should be one).""" if self.do_comments: comments = self.commentapi.get_comments(request_id=req.reqid) for c in comments.values(): m = self.comment_marker_re.match(c['comment']) if m and (state is None or state == m.group('state')): return c['id'], m.group('state'), m.group('result'), c['comment'] return None, None, None, None def check_action__default(self, req, a): self.logger.info("unhandled request type %s"%a.type) self.needs_release_manager = True return True