コード例 #1
0
    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 = {}
コード例 #2
0
    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
コード例 #3
0
ファイル: leaper.py プロジェクト: wengel/osc-plugin-factory
    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
コード例 #4
0
    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.
コード例 #5
0
ファイル: leaper.py プロジェクト: wengel/osc-plugin-factory
    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
コード例 #6
0
ファイル: leaper.py プロジェクト: coogor/osc-plugin-factory
 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'
コード例 #7
0
    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)
コード例 #8
0
ファイル: leaper.py プロジェクト: plusky/osc-plugin-factory
    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 = {}
コード例 #9
0
ファイル: leaper.py プロジェクト: nirmoy/osc-plugin-factory
    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)
コード例 #10
0
    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)
コード例 #11
0
    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.
コード例 #12
0
ファイル: leaper.py プロジェクト: nirmoy/osc-plugin-factory
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
コード例 #13
0
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'])
コード例 #14
0
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'])
コード例 #15
0
ファイル: leaper.py プロジェクト: wengel/osc-plugin-factory
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
コード例 #16
0
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'])
コード例 #17
0
ファイル: leaper.py プロジェクト: plusky/osc-plugin-factory
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
コード例 #18
0
ファイル: leaper.py プロジェクト: coogor/osc-plugin-factory
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
コード例 #19
0
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)
コード例 #20
0
ファイル: leaper.py プロジェクト: wengel/osc-plugin-factory
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
コード例 #21
0
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