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 __init__(self, *args, **kwargs): ReviewBot.ReviewBot.__init__(self, *args, **kwargs) # ReviewBot options. self.only_one_action = True self.maintbot = MaintenanceChecker(*args, **kwargs) self.skip_add_reviews = False
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 setUp(self): """ Initialize the configuration """ super().setUp() httpretty.reset() httpretty.enable() logging.basicConfig() self.logger = logging.getLogger(__file__) self.logger.setLevel(logging.DEBUG) self.checker = MaintenanceChecker(apiurl = APIURL, user = '******', logger = self.logger) self.checker.override_allow = False # Test setup cannot handle.
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 setUp(self): """ Initialize the configuration """ httpretty.reset() httpretty.enable() oscrc = os.path.join(FIXTURES, 'oscrc') osc.core.conf.get_config(override_conffile=oscrc, override_no_keyring=True, override_no_gnome_keyring=True) #osc.conf.config['debug'] = 1 logging.basicConfig() self.logger = logging.getLogger(__file__) self.logger.setLevel(logging.DEBUG) self.checker = MaintenanceChecker(apiurl = APIURL, \ user = '******', \ logger = self.logger)
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 __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 setUp(self): """ Initialize the configuration """ httpretty.reset() httpretty.enable() oscrc = os.path.join(FIXTURES, "oscrc") osc.core.conf.get_config(override_conffile=oscrc, override_no_keyring=True, override_no_gnome_keyring=True) # osc.conf.config['debug'] = 1 logging.basicConfig() self.logger = logging.getLogger(__file__) self.logger.setLevel(logging.DEBUG) self.checker = MaintenanceChecker(apiurl=APIURL, user="******", logger=self.logger)
def setUp(self): """ Initialize the configuration """ httpretty.reset() httpretty.enable() oscrc = os.path.join(FIXTURES, 'oscrc') osc.core.conf.get_config(override_conffile=oscrc, override_no_keyring=True, override_no_gnome_keyring=True) #osc.conf.config['debug'] = 1 logging.basicConfig() self.logger = logging.getLogger(__file__) self.logger.setLevel(logging.DEBUG) self.checker = MaintenanceChecker(apiurl = APIURL, \ user = '******', \ logger = self.logger) self.checker.override_allow = False # Test setup cannot handle.
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
class TestMaintenance(OBSLocal.TestCase): def setUp(self): """ Initialize the configuration """ super().setUp() httpretty.reset() httpretty.enable() logging.basicConfig() self.logger = logging.getLogger(__file__) self.logger.setLevel(logging.DEBUG) self.checker = MaintenanceChecker(apiurl=APIURL, user='******', logger=self.logger) self.checker.override_allow = False # Test setup cannot handle. def test_non_maintainer_submit(self): """same as above but already has devel project as reviewer """ httpretty.register_uri(httpretty.GET, APIURL + '/search/request', body=""" <collection matches="1"> <request id="261355" creator="brassh"> <action type="maintenance_incident"> <source project="home:brassh" package="mysql-workbench" rev="857c77d2ba1d347b6dc50a1e5bcb74e1"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:13.2:Update"/> </action> <state name="review" who="lnussel_factory" when="2014-11-13T10:46:52"> <comment></comment> </state> <review state="new" by_user="******"> <comment></comment> </review> <history who="brassh" when="2014-11-13T09:18:19"> <description>Request created</description> <comment>...</comment> </history> <history who="lnussel_factory" when="2014-11-13T10:46:52"> <description>Request got a new review request</description> </history> <description>...</description> </request> </collection> """) httpretty.register_uri(httpretty.GET, APIURL + "/request/261355", match_querystring=True, body=""" <request id="261355" creator="brassh"> <action type="maintenance_incident"> <source project="home:brassh" package="mysql-workbench" rev="857c77d2ba1d347b6dc50a1e5bcb74e1"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:13.2:Update"/> </action> <state name="review" who="lnussel_factory" when="2014-11-13T10:46:52"> <comment></comment> </state> <review state="new" by_user="******"> <comment></comment> </review> <history who="brassh" when="2014-11-13T09:18:19"> <description>Request created</description> <comment>...</comment> </history> <history who="lnussel_factory" when="2014-11-13T10:46:52"> <description>Request got a new review request</description> </history> <description>...</description> </request> """) httpretty.register_uri(httpretty.GET, APIURL + "/source/home:brassh/mysql-workbench", match_querystring=True, body=""" <directory name="mysql-workbench" rev="6" vrev="6" srcmd5="858204decf53f923d5574dbe6ae63b15"> <linkinfo project="openSUSE:13.2" package="mysql-workbench" srcmd5="ed9c3b12388cbd14868eb3faabe34685" baserev="ed9c3b12388cbd14868eb3faabe34685" xsrcmd5="08bfb4f40cb1e2de8f9cd4633bf02eb1" lsrcmd5="858204decf53f923d5574dbe6ae63b15" /> <serviceinfo code="succeeded" xsrcmd5="6ec4305a8e5363e26a7f4895a0ae12d2" /> <entry name="_link" md5="85ef5fb38ca1ec7c300311fda9f4b3d1" size="121" mtime="1414567341" /> <entry name="mysql-workbench-community-6.1.7-src.tar.gz" md5="ac059e239869fb77bf5d7a1f5845a8af" size="24750696" mtime="1404405925" /> <entry name="mysql-workbench-ctemplate.patch" md5="06ccba1f8275cd9408f515828ecede19" size="1322" mtime="1404658323" /> <entry name="mysql-workbench-glib.patch" md5="67fd7d8e3503ce0909381bde747c8a1e" size="1785" mtime="1415732509" /> <entry name="mysql-workbench-mysql_options4.patch" md5="9c07dfe1b94af95daf3e16bd6a161684" size="910" mtime="1404658324" /> <entry name="mysql-workbench-no-check-for-updates.patch" md5="1f0c9514ff8218d361ea46d3031b2b64" size="1139" mtime="1404658324" /> <entry name="mysql-workbench.changes" md5="26bc54777e6a261816b72f64c69630e4" size="13354" mtime="1415747835" /> <entry name="mysql-workbench.spec" md5="88b562a93f01b842a5798f809e3c8188" size="7489" mtime="1415745943" /> <entry name="openSUSE_(Vendor_Package).xml" md5="ab041af98d7748c216e7e5787ec36f65" size="743" mtime="1315923090" /> <entry name="patch-desktop-categories.patch" md5="c24b3283573c34a5e072be122388f8e1" size="391" mtime="1376991147" /> </directory> """) result = {'devel_review_added': None} def change_request(result, method, uri, headers): query = parse_qs(urlparse(uri).query) if query == { 'by_user': ['maintbot'], 'cmd': ['changereviewstate'], 'newstate': ['accepted'] }: result['devel_review_added'] = True return (200, headers, '<status code="ok"/>') httpretty.register_uri(httpretty.POST, APIURL + "/request/261355", body=lambda method, uri, headers: change_request(result, method, uri, headers)) httpretty.register_uri( httpretty.GET, APIURL + "/search/owner?project=openSUSE:13.2:Update&binary=mysql-workbench", match_querystring=True, body=""" <collection/> """) httpretty.register_uri(httpretty.GET, APIURL + "/search/owner?binary=mysql-workbench", match_querystring=True, body=""" <collection> <owner rootproject="openSUSE" project="server:database" package="mysql-workbench"> <person name="Gankov" role="maintainer"/> <person name="bruno_friedmann" role="maintainer"/> </owner> </collection> """) self.checker.requests = [] self.checker.set_request_ids_search_review() self.checker.check_requests() self.assertTrue(result['devel_review_added']) def test_non_maintainer_double_review(self): httpretty.register_uri(httpretty.GET, APIURL + '/search/request', body=""" <collection matches="1"> <request id="261355" creator="brassh"> <action type="maintenance_incident"> <source project="home:brassh" package="mysql-workbench" rev="857c77d2ba1d347b6dc50a1e5bcb74e1"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:13.2:Update"/> </action> <state name="review" who="lnussel_factory" when="2014-11-13T10:46:52"> <comment></comment> </state> <review state="new" by_user="******"> <comment></comment> </review> <review state="new" by_package="mysql-workbench" by_project="server:database"> <comment>review by devel project</comment> </review> <history who="brassh" when="2014-11-13T09:18:19"> <description>Request created</description> <comment>...</comment> </history> <history who="lnussel_factory" when="2014-11-13T10:46:52"> <description>Request got a new review request</description> </history> <description>...</description> </request> </collection> """) httpretty.register_uri(httpretty.GET, APIURL + "/request/261355", match_querystring=True, body=""" <request id="261355" creator="brassh"> <action type="maintenance_incident"> <source project="home:brassh" package="mysql-workbench" rev="857c77d2ba1d347b6dc50a1e5bcb74e1"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:13.2:Update"/> </action> <state name="review" who="lnussel_factory" when="2014-11-13T10:46:52"> <comment></comment> </state> <review state="new" by_user="******"> <comment></comment> </review> <review state="new" by_package="mysql-workbench" by_project="server:database"> <comment>review by devel project</comment> </review> <history who="brassh" when="2014-11-13T09:18:19"> <description>Request created</description> <comment>...</comment> </history> <history who="lnussel_factory" when="2014-11-13T10:46:52"> <description>Request got a new review request</description> </history> <description>...</description> </request> """) httpretty.register_uri(httpretty.GET, APIURL + "/source/home:brassh/mysql-workbench", match_querystring=True, body=""" <directory name="mysql-workbench" rev="6" vrev="6" srcmd5="858204decf53f923d5574dbe6ae63b15"> <linkinfo project="openSUSE:13.2" package="mysql-workbench" srcmd5="ed9c3b12388cbd14868eb3faabe34685" baserev="ed9c3b12388cbd14868eb3faabe34685" xsrcmd5="08bfb4f40cb1e2de8f9cd4633bf02eb1" lsrcmd5="858204decf53f923d5574dbe6ae63b15" /> <serviceinfo code="succeeded" xsrcmd5="6ec4305a8e5363e26a7f4895a0ae12d2" /> <entry name="_link" md5="85ef5fb38ca1ec7c300311fda9f4b3d1" size="121" mtime="1414567341" /> <entry name="mysql-workbench-community-6.1.7-src.tar.gz" md5="ac059e239869fb77bf5d7a1f5845a8af" size="24750696" mtime="1404405925" /> <entry name="mysql-workbench-ctemplate.patch" md5="06ccba1f8275cd9408f515828ecede19" size="1322" mtime="1404658323" /> <entry name="mysql-workbench-glib.patch" md5="67fd7d8e3503ce0909381bde747c8a1e" size="1785" mtime="1415732509" /> <entry name="mysql-workbench-mysql_options4.patch" md5="9c07dfe1b94af95daf3e16bd6a161684" size="910" mtime="1404658324" /> <entry name="mysql-workbench-no-check-for-updates.patch" md5="1f0c9514ff8218d361ea46d3031b2b64" size="1139" mtime="1404658324" /> <entry name="mysql-workbench.changes" md5="26bc54777e6a261816b72f64c69630e4" size="13354" mtime="1415747835" /> <entry name="mysql-workbench.spec" md5="88b562a93f01b842a5798f809e3c8188" size="7489" mtime="1415745943" /> <entry name="openSUSE_(Vendor_Package).xml" md5="ab041af98d7748c216e7e5787ec36f65" size="743" mtime="1315923090" /> <entry name="patch-desktop-categories.patch" md5="c24b3283573c34a5e072be122388f8e1" size="391" mtime="1376991147" /> </directory> """) result = {'devel_review_added': None} def change_request(result, method, uri, headers): u = urlparse(uri) if u.query == 'by_package=mysql-workbench&cmd=addreview&by_project=server%3Adatabase': result['devel_review_added'] = True return (200, headers, '<status code="ok"/>') httpretty.register_uri(httpretty.POST, APIURL + "/request/261355", body=lambda method, uri, headers: change_request(result, method, uri, headers)) httpretty.register_uri( httpretty.GET, APIURL + "/search/owner?project=openSUSE:13.2:Update&binary=mysql-workbench", match_querystring=True, body=""" <collection/> """) httpretty.register_uri(httpretty.GET, APIURL + "/search/owner?binary=mysql-workbench", match_querystring=True, body=""" <collection> <owner rootproject="openSUSE" project="server:database" package="mysql-workbench"> <person name="Gankov" role="maintainer"/> <person name="bruno_friedmann" role="maintainer"/> </owner> </collection> """) self.checker.requests = [] self.checker.set_request_ids_search_review() self.checker.check_requests() self.assertFalse(result['devel_review_added'])
class TestMaintenance(unittest.TestCase): def setUp(self): """ Initialize the configuration """ httpretty.reset() httpretty.enable() oscrc = os.path.join(FIXTURES, 'oscrc') osc.core.conf.get_config(override_conffile=oscrc, override_no_keyring=True, override_no_gnome_keyring=True) #osc.conf.config['debug'] = 1 logging.basicConfig() self.logger = logging.getLogger(__file__) self.logger.setLevel(logging.DEBUG) self.checker = MaintenanceChecker(apiurl = APIURL, \ user = '******', \ logger = self.logger) self.checker.override_allow = False # Test setup cannot handle. def test_non_maintainer_submit(self): """same as above but already has devel project as reviewer """ httpretty.register_uri(httpretty.GET, APIURL + '/search/request', body = """ <collection matches="1"> <request id="261355" creator="brassh"> <action type="maintenance_incident"> <source project="home:brassh" package="mysql-workbench" rev="857c77d2ba1d347b6dc50a1e5bcb74e1"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:13.2:Update"/> </action> <state name="review" who="lnussel_factory" when="2014-11-13T10:46:52"> <comment></comment> </state> <review state="new" by_user="******"> <comment></comment> </review> <history who="brassh" when="2014-11-13T09:18:19"> <description>Request created</description> <comment>...</comment> </history> <history who="lnussel_factory" when="2014-11-13T10:46:52"> <description>Request got a new review request</description> </history> <description>...</description> </request> </collection> """) httpretty.register_uri(httpretty.GET, APIURL + "/request/261355", match_querystring = True, body = """ <request id="261355" creator="brassh"> <action type="maintenance_incident"> <source project="home:brassh" package="mysql-workbench" rev="857c77d2ba1d347b6dc50a1e5bcb74e1"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:13.2:Update"/> </action> <state name="review" who="lnussel_factory" when="2014-11-13T10:46:52"> <comment></comment> </state> <review state="new" by_user="******"> <comment></comment> </review> <history who="brassh" when="2014-11-13T09:18:19"> <description>Request created</description> <comment>...</comment> </history> <history who="lnussel_factory" when="2014-11-13T10:46:52"> <description>Request got a new review request</description> </history> <description>...</description> </request> """) httpretty.register_uri(httpretty.GET, APIURL + "/source/home:brassh/mysql-workbench", match_querystring = True, body = """ <directory name="mysql-workbench" rev="6" vrev="6" srcmd5="858204decf53f923d5574dbe6ae63b15"> <linkinfo project="openSUSE:13.2" package="mysql-workbench" srcmd5="ed9c3b12388cbd14868eb3faabe34685" baserev="ed9c3b12388cbd14868eb3faabe34685" xsrcmd5="08bfb4f40cb1e2de8f9cd4633bf02eb1" lsrcmd5="858204decf53f923d5574dbe6ae63b15" /> <serviceinfo code="succeeded" xsrcmd5="6ec4305a8e5363e26a7f4895a0ae12d2" /> <entry name="_link" md5="85ef5fb38ca1ec7c300311fda9f4b3d1" size="121" mtime="1414567341" /> <entry name="mysql-workbench-community-6.1.7-src.tar.gz" md5="ac059e239869fb77bf5d7a1f5845a8af" size="24750696" mtime="1404405925" /> <entry name="mysql-workbench-ctemplate.patch" md5="06ccba1f8275cd9408f515828ecede19" size="1322" mtime="1404658323" /> <entry name="mysql-workbench-glib.patch" md5="67fd7d8e3503ce0909381bde747c8a1e" size="1785" mtime="1415732509" /> <entry name="mysql-workbench-mysql_options4.patch" md5="9c07dfe1b94af95daf3e16bd6a161684" size="910" mtime="1404658324" /> <entry name="mysql-workbench-no-check-for-updates.patch" md5="1f0c9514ff8218d361ea46d3031b2b64" size="1139" mtime="1404658324" /> <entry name="mysql-workbench.changes" md5="26bc54777e6a261816b72f64c69630e4" size="13354" mtime="1415747835" /> <entry name="mysql-workbench.spec" md5="88b562a93f01b842a5798f809e3c8188" size="7489" mtime="1415745943" /> <entry name="openSUSE_(Vendor_Package).xml" md5="ab041af98d7748c216e7e5787ec36f65" size="743" mtime="1315923090" /> <entry name="patch-desktop-categories.patch" md5="c24b3283573c34a5e072be122388f8e1" size="391" mtime="1376991147" /> </directory> """) result = { 'devel_review_added' : None } def change_request(result, method, uri, headers): query = parse_qs(urlparse(uri).query) if query == {'by_user': ['maintbot'], 'cmd': ['changereviewstate'], 'newstate': ['accepted']}: result['devel_review_added'] = True return (200, headers, '<status code="ok"/>') httpretty.register_uri(httpretty.POST, APIURL + "/request/261355", body = lambda method, uri, headers: change_request(result, method, uri, headers)) httpretty.register_uri(httpretty.GET, APIURL + "/search/owner?project=openSUSE:13.2:Update&binary=mysql-workbench", match_querystring = True, body = """ <collection/> """) httpretty.register_uri(httpretty.GET, APIURL + "/search/owner?binary=mysql-workbench", match_querystring = True, body = """ <collection> <owner rootproject="openSUSE" project="server:database" package="mysql-workbench"> <person name="Gankov" role="maintainer"/> <person name="bruno_friedmann" role="maintainer"/> </owner> </collection> """) self.checker.requests = [] self.checker.set_request_ids_search_review() self.checker.check_requests() self.assertTrue(result['devel_review_added']) def test_non_maintainer_double_review(self): httpretty.register_uri(httpretty.GET, APIURL + '/search/request', body = """ <collection matches="1"> <request id="261355" creator="brassh"> <action type="maintenance_incident"> <source project="home:brassh" package="mysql-workbench" rev="857c77d2ba1d347b6dc50a1e5bcb74e1"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:13.2:Update"/> </action> <state name="review" who="lnussel_factory" when="2014-11-13T10:46:52"> <comment></comment> </state> <review state="new" by_user="******"> <comment></comment> </review> <review state="new" by_package="mysql-workbench" by_project="server:database"> <comment>review by devel project</comment> </review> <history who="brassh" when="2014-11-13T09:18:19"> <description>Request created</description> <comment>...</comment> </history> <history who="lnussel_factory" when="2014-11-13T10:46:52"> <description>Request got a new review request</description> </history> <description>...</description> </request> </collection> """) httpretty.register_uri(httpretty.GET, APIURL + "/request/261355", match_querystring = True, body = """ <request id="261355" creator="brassh"> <action type="maintenance_incident"> <source project="home:brassh" package="mysql-workbench" rev="857c77d2ba1d347b6dc50a1e5bcb74e1"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:13.2:Update"/> </action> <state name="review" who="lnussel_factory" when="2014-11-13T10:46:52"> <comment></comment> </state> <review state="new" by_user="******"> <comment></comment> </review> <review state="new" by_package="mysql-workbench" by_project="server:database"> <comment>review by devel project</comment> </review> <history who="brassh" when="2014-11-13T09:18:19"> <description>Request created</description> <comment>...</comment> </history> <history who="lnussel_factory" when="2014-11-13T10:46:52"> <description>Request got a new review request</description> </history> <description>...</description> </request> """) httpretty.register_uri(httpretty.GET, APIURL + "/source/home:brassh/mysql-workbench", match_querystring = True, body = """ <directory name="mysql-workbench" rev="6" vrev="6" srcmd5="858204decf53f923d5574dbe6ae63b15"> <linkinfo project="openSUSE:13.2" package="mysql-workbench" srcmd5="ed9c3b12388cbd14868eb3faabe34685" baserev="ed9c3b12388cbd14868eb3faabe34685" xsrcmd5="08bfb4f40cb1e2de8f9cd4633bf02eb1" lsrcmd5="858204decf53f923d5574dbe6ae63b15" /> <serviceinfo code="succeeded" xsrcmd5="6ec4305a8e5363e26a7f4895a0ae12d2" /> <entry name="_link" md5="85ef5fb38ca1ec7c300311fda9f4b3d1" size="121" mtime="1414567341" /> <entry name="mysql-workbench-community-6.1.7-src.tar.gz" md5="ac059e239869fb77bf5d7a1f5845a8af" size="24750696" mtime="1404405925" /> <entry name="mysql-workbench-ctemplate.patch" md5="06ccba1f8275cd9408f515828ecede19" size="1322" mtime="1404658323" /> <entry name="mysql-workbench-glib.patch" md5="67fd7d8e3503ce0909381bde747c8a1e" size="1785" mtime="1415732509" /> <entry name="mysql-workbench-mysql_options4.patch" md5="9c07dfe1b94af95daf3e16bd6a161684" size="910" mtime="1404658324" /> <entry name="mysql-workbench-no-check-for-updates.patch" md5="1f0c9514ff8218d361ea46d3031b2b64" size="1139" mtime="1404658324" /> <entry name="mysql-workbench.changes" md5="26bc54777e6a261816b72f64c69630e4" size="13354" mtime="1415747835" /> <entry name="mysql-workbench.spec" md5="88b562a93f01b842a5798f809e3c8188" size="7489" mtime="1415745943" /> <entry name="openSUSE_(Vendor_Package).xml" md5="ab041af98d7748c216e7e5787ec36f65" size="743" mtime="1315923090" /> <entry name="patch-desktop-categories.patch" md5="c24b3283573c34a5e072be122388f8e1" size="391" mtime="1376991147" /> </directory> """) result = { 'devel_review_added' : None } def change_request(result, method, uri, headers): u = urlparse(uri) if u.query == 'by_package=mysql-workbench&cmd=addreview&by_project=server%3Adatabase': result['devel_review_added'] = True return (200, headers, '<status code="ok"/>') httpretty.register_uri(httpretty.POST, APIURL + "/request/261355", body = lambda method, uri, headers: change_request(result, method, uri, headers)) httpretty.register_uri(httpretty.GET, APIURL + "/search/owner?project=openSUSE:13.2:Update&binary=mysql-workbench", match_querystring = True, body = """ <collection/> """) httpretty.register_uri(httpretty.GET, APIURL + "/search/owner?binary=mysql-workbench", match_querystring = True, body = """ <collection> <owner rootproject="openSUSE" project="server:database" package="mysql-workbench"> <person name="Gankov" role="maintainer"/> <person name="bruno_friedmann" role="maintainer"/> </owner> </collection> """) self.checker.requests = [] self.checker.set_request_ids_search_review() self.checker.check_requests() self.assertFalse(result['devel_review_added']) def test_backports_submit(self): httpretty.register_uri(httpretty.GET, APIURL + '/search/request', body = """ <collection matches="1"> <request id="261411" creator="lnussel"> <action type="maintenance_incident"> <source project="home:lnussel:branches:openSUSE:Backports:SLE-12" package="plan" rev="71e76daf2c2e9ddb0b9208f54a14f608"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:Backports:SLE-12"/> </action> <state name="review" who="lnussel" when="2014-11-13T13:22:02"> <comment></comment> </state> <review state="new" by_user="******"/> <history who="lnussel" when="2014-11-13T13:22:02"> <description>Request created</description> <comment>test update</comment> </history> <description>test update</description> </request> </collection> """) httpretty.register_uri(httpretty.GET, APIURL + "/request/261411", body = """ <request id="261411" creator="lnussel"> <action type="maintenance_incident"> <source project="home:lnussel:branches:openSUSE:Backports:SLE-12" package="plan" rev="71e76daf2c2e9ddb0b9208f54a14f608"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:Backports:SLE-12"/> </action> <state name="review" who="lnussel" when="2014-11-13T13:22:02"> <comment></comment> </state> <review state="new" by_user="******"/> <history who="lnussel" when="2014-11-13T13:22:02"> <description>Request created</description> <comment>test update</comment> </history> <description>test update</description> </request> """) httpretty.register_uri(httpretty.GET, APIURL + "/source/home:lnussel:branches:openSUSE:Backports:SLE-12/plan", body = """ <directory name="plan" rev="1" vrev="1" srcmd5="b4ed19dc30c1b328168bc62a81ec6998"> <linkinfo project="home:lnussel:plan" package="plan" srcmd5="7a2353f73b29dba970702053229542a0" baserev="7a2353f73b29dba970702053229542a0" xsrcmd5="71e76daf2c2e9ddb0b9208f54a14f608" lsrcmd5="b4ed19dc30c1b328168bc62a81ec6998" /> <entry name="_link" md5="91f81d88456818a18a7332999fb2da18" size="125" mtime="1415807350" /> <entry name="plan.spec" md5="b6814215f6d2e8559b43de9a214b2cbd" size="8103" mtime="1413627959" /> </directory> """) httpretty.register_uri(httpretty.GET, APIURL + '/search/owner', body = """ <collection/> """) result = { 'factory_review_added' : None } def change_request(result, method, uri, headers): query = parse_qs(urlparse(uri).query) if query == { 'cmd': ['addreview'], 'by_user': ['factory-source'] }: result['factory_review_added'] = True return (200, headers, '<status code="ok"/>') httpretty.register_uri(httpretty.POST, APIURL + "/request/261411", body = lambda method, uri, headers: change_request(result, method, uri, headers)) self.checker.requests = [] self.checker.set_request_ids_search_review() self.checker.check_requests() self.assertTrue(result['factory_review_added'])
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 TestMaintenance(unittest.TestCase): def setUp(self): """ Initialize the configuration """ httpretty.reset() httpretty.enable() oscrc = os.path.join(FIXTURES, 'oscrc') osc.core.conf.get_config(override_conffile=oscrc, override_no_keyring=True, override_no_gnome_keyring=True) #osc.conf.config['debug'] = 1 logging.basicConfig() self.logger = logging.getLogger(__file__) self.logger.setLevel(logging.DEBUG) self.checker = MaintenanceChecker(apiurl = APIURL, \ user = '******', \ logger = self.logger) def test_non_maintainer_submit(self): """same as above but already has devel project as reviewer """ httpretty.register_uri( httpretty.GET, rr("/search/request?withfullhistory=1&match=state%2F%40name%3D%27review%27+and+review%5B%40by_user%3D%27maintbot%27+and+%40state%3D%27new%27%5D" ), match_querystring=True, body=""" <collection matches="1"> <request id="261355" creator="brassh"> <action type="maintenance_incident"> <source project="home:brassh" package="mysql-workbench" rev="857c77d2ba1d347b6dc50a1e5bcb74e1"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:13.2:Update"/> </action> <state name="review" who="lnussel_factory" when="2014-11-13T10:46:52"> <comment></comment> </state> <review state="new" by_user="******"> <comment></comment> </review> <history who="brassh" when="2014-11-13T09:18:19"> <description>Request created</description> <comment>...</comment> </history> <history who="lnussel_factory" when="2014-11-13T10:46:52"> <description>Request got a new review request</description> </history> <description>...</description> </request> </collection> """) httpretty.register_uri(httpretty.GET, APIURL + "/request/261355", match_querystring=True, body=""" <request id="261355" creator="brassh"> <action type="maintenance_incident"> <source project="home:brassh" package="mysql-workbench" rev="857c77d2ba1d347b6dc50a1e5bcb74e1"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:13.2:Update"/> </action> <state name="review" who="lnussel_factory" when="2014-11-13T10:46:52"> <comment></comment> </state> <review state="new" by_user="******"> <comment></comment> </review> <history who="brassh" when="2014-11-13T09:18:19"> <description>Request created</description> <comment>...</comment> </history> <history who="lnussel_factory" when="2014-11-13T10:46:52"> <description>Request got a new review request</description> </history> <description>...</description> </request> """) httpretty.register_uri(httpretty.GET, APIURL + "/source/home:brassh/mysql-workbench", match_querystring=True, body=""" <directory name="mysql-workbench" rev="6" vrev="6" srcmd5="858204decf53f923d5574dbe6ae63b15"> <linkinfo project="openSUSE:13.2" package="mysql-workbench" srcmd5="ed9c3b12388cbd14868eb3faabe34685" baserev="ed9c3b12388cbd14868eb3faabe34685" xsrcmd5="08bfb4f40cb1e2de8f9cd4633bf02eb1" lsrcmd5="858204decf53f923d5574dbe6ae63b15" /> <serviceinfo code="succeeded" xsrcmd5="6ec4305a8e5363e26a7f4895a0ae12d2" /> <entry name="_link" md5="85ef5fb38ca1ec7c300311fda9f4b3d1" size="121" mtime="1414567341" /> <entry name="mysql-workbench-community-6.1.7-src.tar.gz" md5="ac059e239869fb77bf5d7a1f5845a8af" size="24750696" mtime="1404405925" /> <entry name="mysql-workbench-ctemplate.patch" md5="06ccba1f8275cd9408f515828ecede19" size="1322" mtime="1404658323" /> <entry name="mysql-workbench-glib.patch" md5="67fd7d8e3503ce0909381bde747c8a1e" size="1785" mtime="1415732509" /> <entry name="mysql-workbench-mysql_options4.patch" md5="9c07dfe1b94af95daf3e16bd6a161684" size="910" mtime="1404658324" /> <entry name="mysql-workbench-no-check-for-updates.patch" md5="1f0c9514ff8218d361ea46d3031b2b64" size="1139" mtime="1404658324" /> <entry name="mysql-workbench.changes" md5="26bc54777e6a261816b72f64c69630e4" size="13354" mtime="1415747835" /> <entry name="mysql-workbench.spec" md5="88b562a93f01b842a5798f809e3c8188" size="7489" mtime="1415745943" /> <entry name="openSUSE_(Vendor_Package).xml" md5="ab041af98d7748c216e7e5787ec36f65" size="743" mtime="1315923090" /> <entry name="patch-desktop-categories.patch" md5="c24b3283573c34a5e072be122388f8e1" size="391" mtime="1376991147" /> </directory> """) result = {'devel_review_added': None} def change_request(result, method, uri, headers): u = urlparse.urlparse(uri) if u.query == 'by_package=mysql-workbench&cmd=addreview&by_project=server%3Adatabase': result['devel_review_added'] = True return (200, headers, '<status code="ok"/>') httpretty.register_uri(httpretty.POST, APIURL + "/request/261355", body=lambda method, uri, headers: change_request(result, method, uri, headers)) httpretty.register_uri( httpretty.GET, APIURL + "/search/owner?project=openSUSE:13.2:Update&binary=mysql-workbench", match_querystring=True, body=""" <collection/> """) httpretty.register_uri(httpretty.GET, APIURL + "/search/owner?binary=mysql-workbench", match_querystring=True, body=""" <collection> <owner rootproject="openSUSE" project="server:database" package="mysql-workbench"> <person name="Gankov" role="maintainer"/> <person name="bruno_friedmann" role="maintainer"/> </owner> </collection> """) self.checker.requests = [] self.checker.set_request_ids_search_review() self.checker.check_requests() self.assertTrue(result['devel_review_added']) def test_non_maintainer_double_review(self): httpretty.register_uri( httpretty.GET, rr("/search/request?withfullhistory=1&match=state%2F%40name%3D%27review%27+and+review%5B%40by_user%3D%27maintbot%27+and+%40state%3D%27new%27%5D" ), match_querystring=True, body=""" <collection matches="1"> <request id="261355" creator="brassh"> <action type="maintenance_incident"> <source project="home:brassh" package="mysql-workbench" rev="857c77d2ba1d347b6dc50a1e5bcb74e1"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:13.2:Update"/> </action> <state name="review" who="lnussel_factory" when="2014-11-13T10:46:52"> <comment></comment> </state> <review state="new" by_user="******"> <comment></comment> </review> <review state="new" by_package="mysql-workbench" by_project="server:database"> <comment>review by devel project</comment> </review> <history who="brassh" when="2014-11-13T09:18:19"> <description>Request created</description> <comment>...</comment> </history> <history who="lnussel_factory" when="2014-11-13T10:46:52"> <description>Request got a new review request</description> </history> <description>...</description> </request> </collection> """) httpretty.register_uri(httpretty.GET, APIURL + "/request/261355", match_querystring=True, body=""" <request id="261355" creator="brassh"> <action type="maintenance_incident"> <source project="home:brassh" package="mysql-workbench" rev="857c77d2ba1d347b6dc50a1e5bcb74e1"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:13.2:Update"/> </action> <state name="review" who="lnussel_factory" when="2014-11-13T10:46:52"> <comment></comment> </state> <review state="new" by_user="******"> <comment></comment> </review> <review state="new" by_package="mysql-workbench" by_project="server:database"> <comment>review by devel project</comment> </review> <history who="brassh" when="2014-11-13T09:18:19"> <description>Request created</description> <comment>...</comment> </history> <history who="lnussel_factory" when="2014-11-13T10:46:52"> <description>Request got a new review request</description> </history> <description>...</description> </request> """) httpretty.register_uri(httpretty.GET, APIURL + "/source/home:brassh/mysql-workbench", match_querystring=True, body=""" <directory name="mysql-workbench" rev="6" vrev="6" srcmd5="858204decf53f923d5574dbe6ae63b15"> <linkinfo project="openSUSE:13.2" package="mysql-workbench" srcmd5="ed9c3b12388cbd14868eb3faabe34685" baserev="ed9c3b12388cbd14868eb3faabe34685" xsrcmd5="08bfb4f40cb1e2de8f9cd4633bf02eb1" lsrcmd5="858204decf53f923d5574dbe6ae63b15" /> <serviceinfo code="succeeded" xsrcmd5="6ec4305a8e5363e26a7f4895a0ae12d2" /> <entry name="_link" md5="85ef5fb38ca1ec7c300311fda9f4b3d1" size="121" mtime="1414567341" /> <entry name="mysql-workbench-community-6.1.7-src.tar.gz" md5="ac059e239869fb77bf5d7a1f5845a8af" size="24750696" mtime="1404405925" /> <entry name="mysql-workbench-ctemplate.patch" md5="06ccba1f8275cd9408f515828ecede19" size="1322" mtime="1404658323" /> <entry name="mysql-workbench-glib.patch" md5="67fd7d8e3503ce0909381bde747c8a1e" size="1785" mtime="1415732509" /> <entry name="mysql-workbench-mysql_options4.patch" md5="9c07dfe1b94af95daf3e16bd6a161684" size="910" mtime="1404658324" /> <entry name="mysql-workbench-no-check-for-updates.patch" md5="1f0c9514ff8218d361ea46d3031b2b64" size="1139" mtime="1404658324" /> <entry name="mysql-workbench.changes" md5="26bc54777e6a261816b72f64c69630e4" size="13354" mtime="1415747835" /> <entry name="mysql-workbench.spec" md5="88b562a93f01b842a5798f809e3c8188" size="7489" mtime="1415745943" /> <entry name="openSUSE_(Vendor_Package).xml" md5="ab041af98d7748c216e7e5787ec36f65" size="743" mtime="1315923090" /> <entry name="patch-desktop-categories.patch" md5="c24b3283573c34a5e072be122388f8e1" size="391" mtime="1376991147" /> </directory> """) result = {'devel_review_added': None} def change_request(result, method, uri, headers): u = urlparse.urlparse(uri) if u.query == 'by_package=mysql-workbench&cmd=addreview&by_project=server%3Adatabase': result['devel_review_added'] = True return (200, headers, '<status code="ok"/>') httpretty.register_uri(httpretty.POST, APIURL + "/request/261355", body=lambda method, uri, headers: change_request(result, method, uri, headers)) httpretty.register_uri( httpretty.GET, APIURL + "/search/owner?project=openSUSE:13.2:Update&binary=mysql-workbench", match_querystring=True, body=""" <collection/> """) httpretty.register_uri(httpretty.GET, APIURL + "/search/owner?binary=mysql-workbench", match_querystring=True, body=""" <collection> <owner rootproject="openSUSE" project="server:database" package="mysql-workbench"> <person name="Gankov" role="maintainer"/> <person name="bruno_friedmann" role="maintainer"/> </owner> </collection> """) self.checker.requests = [] self.checker.set_request_ids_search_review() self.checker.check_requests() self.assertFalse(result['devel_review_added']) def test_backports_submit(self): httpretty.register_uri( httpretty.GET, rr("/search/request?withfullhistory=1&match=state%2F%40name%3D%27review%27+and+review%5B%40by_user%3D%27maintbot%27+and+%40state%3D%27new%27%5D" ), match_querystring=True, body=""" <collection matches="1"> <request id="261411" creator="lnussel"> <action type="maintenance_incident"> <source project="home:lnussel:branches:openSUSE:Backports:SLE-12" package="plan" rev="71e76daf2c2e9ddb0b9208f54a14f608"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:Backports:SLE-12"/> </action> <state name="review" who="lnussel" when="2014-11-13T13:22:02"> <comment></comment> </state> <review state="new" by_user="******"/> <history who="lnussel" when="2014-11-13T13:22:02"> <description>Request created</description> <comment>test update</comment> </history> <description>test update</description> </request> </collection> """) httpretty.register_uri(httpretty.GET, APIURL + "/request/261411", body=""" <request id="261411" creator="lnussel"> <action type="maintenance_incident"> <source project="home:lnussel:branches:openSUSE:Backports:SLE-12" package="plan" rev="71e76daf2c2e9ddb0b9208f54a14f608"/> <target project="openSUSE:Maintenance" releaseproject="openSUSE:Backports:SLE-12"/> </action> <state name="review" who="lnussel" when="2014-11-13T13:22:02"> <comment></comment> </state> <review state="new" by_user="******"/> <history who="lnussel" when="2014-11-13T13:22:02"> <description>Request created</description> <comment>test update</comment> </history> <description>test update</description> </request> """) httpretty.register_uri( httpretty.GET, APIURL + "/source/home:lnussel:branches:openSUSE:Backports:SLE-12/plan", body=""" <directory name="plan" rev="1" vrev="1" srcmd5="b4ed19dc30c1b328168bc62a81ec6998"> <linkinfo project="home:lnussel:plan" package="plan" srcmd5="7a2353f73b29dba970702053229542a0" baserev="7a2353f73b29dba970702053229542a0" xsrcmd5="71e76daf2c2e9ddb0b9208f54a14f608" lsrcmd5="b4ed19dc30c1b328168bc62a81ec6998" /> <entry name="_link" md5="91f81d88456818a18a7332999fb2da18" size="125" mtime="1415807350" /> <entry name="plan.spec" md5="b6814215f6d2e8559b43de9a214b2cbd" size="8103" mtime="1413627959" /> </directory> """) httpretty.register_uri( httpretty.GET, APIURL + "/search/owner?project=openSUSE:Backports:SLE-12&binary=plan", match_querystring=True, body=""" <collection/> """) httpretty.register_uri(httpretty.GET, APIURL + "/search/owner?binary=plan", match_querystring=True, body=""" <collection/> """) result = {'factory_review_added': None} def change_request(result, method, uri, headers): u = urlparse.urlparse(uri) if u.query == 'cmd=addreview&by_user=factory-source': result['factory_review_added'] = True return (200, headers, '<status code="ok"/>') httpretty.register_uri(httpretty.POST, APIURL + "/request/261411", body=lambda method, uri, headers: change_request(result, method, uri, headers)) self.checker.requests = [] self.checker.set_request_ids_search_review() self.checker.check_requests() self.assertTrue(result['factory_review_added'])
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) 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) # 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 CheckSource(ReviewBot.ReviewBot): SCRIPT_PATH = os.path.dirname(os.path.realpath(__file__)) def __init__(self, *args, **kwargs): ReviewBot.ReviewBot.__init__(self, *args, **kwargs) # ReviewBot options. self.only_one_action = True self.maintbot = MaintenanceChecker(*args, **kwargs) self.skip_add_reviews = False def target_project_config(self, project): # Load project config and allow for remote entries. self.staging_api(project) config = self.staging_config[project] self.ignore_devel = not bool(config.get('devel-project-enforce', False)) self.review_team = config.get('review-team') self.repo_checker = config.get('repo-checker') self.devel_whitelist = config.get('devel-whitelist', '').split() def check_source_submission(self, source_project, source_package, source_revision, target_project, target_package): super(CheckSource, self).check_source_submission(source_project, source_package, source_revision, target_project, target_package) self.target_project_config(target_project) if not self.ignore_devel: self.logger.info( 'checking if target package exists and has devel project') devel_project, devel_package = devel_project_get( self.apiurl, target_project, target_package) if devel_project: if (source_project != devel_project or source_package != devel_package) and \ not(source_project == target_project and source_package == target_package): # Not from proper devel project/package and not self-submission. self.review_messages[ 'declined'] = 'Expected submission from devel package %s/%s' % ( devel_project, devel_package) return False else: # Check to see if other packages exist with the same source project # which indicates that the project has already been used as devel. if not self.is_devel_project(source_project, target_project): self.review_messages[ 'declined'] = '%s is not a devel project of %s, submit the package to a devel project first' % ( source_project, target_project) return False # Checkout and see if renaming package screws up version parsing. dir = os.path.expanduser('~/co/%s' % self.request.reqid) if os.path.exists(dir): self.logger.warn('directory %s already exists' % dir) shutil.rmtree(dir) os.makedirs(dir) os.chdir(dir) old_info = {'version': None} try: CheckSource.checkout_package(self.apiurl, target_project, target_package, pathname=dir, server_service_files=True, expand_link=True) shutil.rmtree(os.path.join(target_package, '.osc')) os.rename(target_package, '_old') old_info = self.package_source_parse(target_project, target_package) except urllib2.HTTPError: self.logger.error('failed to checkout %s/%s' % (target_project, target_package)) CheckSource.checkout_package(self.apiurl, source_project, source_package, revision=source_revision, pathname=dir, server_service_files=True, expand_link=True) os.rename(source_package, target_package) shutil.rmtree(os.path.join(target_package, '.osc')) new_info = self.package_source_parse(source_project, source_package, source_revision) if new_info['name'] != target_package: shutil.rmtree(dir) self.review_messages[ 'declined'] = "A package submitted as %s has to build as 'Name: %s' - found Name '%s'" % ( target_package, target_package, new_info['name']) return False # We want to see the same package name in the devel project as in the distro; anything else calls for confusion if source_package != target_package: self.review_messages[ 'declined'] = "No in-air renames: The package must be called the same in the devel project as in the target project" return False # Run check_source.pl script and interpret output. source_checker = os.path.join(CheckSource.SCRIPT_PATH, 'check_source.pl') civs = '' new_version = None if old_info['version'] and old_info['version'] != new_info['version']: new_version = new_info['version'] civs += "NEW_VERSION='{}' ".format(new_version) civs += 'LC_ALL=C perl %s _old %s 2>&1' % (source_checker, target_package) p = subprocess.Popen(civs, shell=True, stdout=subprocess.PIPE, close_fds=True) ret = os.waitpid(p.pid, 0)[1] checked = p.stdout.readlines() output = ' '.join(checked).translate(None, '\033') os.chdir('/tmp') # ret = 0 : Good # ret = 1 : Bad # ret = 2 : Bad but can be non-fatal in some cases if ret > 1 and target_project.startswith('openSUSE:Leap:') and ( source_project.startswith('SUSE:SLE-15:') or source_project.startswith('openSUSE:Factory')): pass elif ret != 0: shutil.rmtree(dir) self.review_messages[ 'declined'] = "Output of check script:\n" + output return False shutil.rmtree(dir) self.review_messages['accepted'] = 'Check script succeeded' if len(checked): self.review_messages[ 'accepted'] += "\n\nOutput of check script (non-fatal):\n" + output if not self.skip_add_reviews: if self.review_team is not None: self.add_review(self.request, by_group=self.review_team, msg='Please review sources') if self.only_changes(): self.logger.debug('only .changes modifications') staging_group = self.staging_group(target_project) if staging_group and not self.dryrun: osc.core.change_review_state( self.apiurl, str(self.request.reqid), 'accepted', by_group=staging_group, message= 'skipping the staging process since only .changes modifications' ) elif self.repo_checker is not None: self.add_review(self.request, by_user=self.repo_checker, msg='Please review build success') return True def staging_group(self, project): try: return self.staging_api(project).cstaging_group except urllib2.HTTPError as e: if e.code != 404: raise e return None def is_devel_project(self, source_project, target_project): if source_project in self.devel_whitelist: return True # Allow any projects already used as devel projects for other packages. search = { 'package': "@project='%s' and devel/@project='%s'" % (target_project, source_project), } result = osc.core.search(self.apiurl, **search) return result['package'].attrib['matches'] != '0' @staticmethod def checkout_package(*args, **kwargs): _stdout = sys.stdout sys.stdout = open(os.devnull, 'wb') try: result = osc.core.checkout_package(*args, **kwargs) finally: sys.stdout = _stdout return result def package_source_parse(self, project, package, revision=None): query = {'view': 'info', 'parse': 1} if revision: query['rev'] = revision url = osc.core.makeurl(self.apiurl, ['source', project, package], query) ret = {'name': None, 'version': None} try: xml = ET.parse(osc.core.http_GET(url)).getroot() except urllib2.HTTPError as e: self.logger.error('ERROR in URL %s [%s]' % (url, e)) return ret # ET boolean check fails. if xml.find('name') is not None: ret['name'] = xml.find('name').text if xml.find('version') is not None: ret['version'] = xml.find('version').text return ret def only_changes(self): u = osc.core.makeurl(self.apiurl, ['request', self.request.reqid], { 'cmd': 'diff', 'view': 'xml' }) try: diff = ET.parse(osc.core.http_POST(u)).getroot() for f in diff.findall('action/sourcediff/files/file/*[@name]'): if not f.get('name').endswith('.changes'): return False return True except: pass return False def check_action_add_role(self, request, action): # Decline add_role request (assumed the bot acting on requests to Factory or similar). message = 'Roles to packages are granted in the devel project, not in %s.' % action.tgt_project if action.tgt_package is not None: project, package = devel_project_get(self.apiurl, action.tgt_project, action.tgt_package) message += ' Send this request to {}/{}.'.format(project, package) self.review_messages['declined'] = message return False def check_action_delete(self, request, action): self.target_project_config(action.tgt_project) if action.tgt_repository is not None: if action.tgt_project.startswith('openSUSE:'): self.review_messages['declined'] = 'The repositories in the openSUSE:* namespace ' \ 'are managed by the Release Managers. For suggesting changes, send a mail ' \ 'to [email protected] with an explanation of why the change ' \ 'makes sense.' return False else: self.review_messages[ 'accepted'] = 'unhandled: removing repository' return True try: result = osc.core.show_project_sourceinfo(self.apiurl, action.tgt_project, True, (action.tgt_package)) root = ET.fromstring(result) except urllib2.HTTPError: return None # Decline the delete request if there is another delete/submit request against the same package query = "match=state/@name='new'+and+(action/target/@project='{}'+and+action/target/@package='{}')"\ "+and+(action/@type='delete'+or+action/@type='submit')".format(action.tgt_project, action.tgt_package) url = osc.core.makeurl(self.apiurl, ['search', 'request'], query) matches = ET.parse(osc.core.http_GET(url)).getroot() if int(matches.attrib['matches']) > 1: ids = [rq.attrib['id'] for rq in matches.findall('request')] self.review_messages[ 'declined'] = "There is a pending request %s to %s/%s in process." % ( ','.join(ids), action.tgt_project, action.tgt_package) return False # Decline the delete request against linked package. links = root.findall('sourceinfo/linked') if links is None or len(links) == 0: # Utilize maintbot to add devel project review if necessary. self.maintbot.check_one_request(request) if not self.skip_add_reviews and self.repo_checker is not None: self.add_review(self.request, by_user=self.repo_checker, msg='Is this delete request safe?') return True else: linked = links[0] linked_project = linked.get('project') linked_package = linked.get('package') self.review_messages[ 'declined'] = "This is an incorrect request, it's a linked package to %s/%s" % ( linked_project, linked_package) return False def check_action__default(self, request, action): self.review_messages['accepted'] = 'Unhandled request type %s.' % ( action.type) return True