def test_pushes_within_changes(mocker):
    push_first = {'1': {'changesets': ['a']}}
    other_pushes = {'2': {'changesets': ['b']}, '3': {'changesets': ['c']}}

    retry_get = mocker.patch('mozregression.json_pushes.retry_get')
    response = Mock(json=Mock(side_effect=[push_first, other_pushes]))
    retry_get.return_value = response

    jpushes = JsonPushes()
    pushes = jpushes.pushes_within_changes('fromchset', "tochset")

    assert pushes[0].push_id == '1'
    assert pushes[0].changeset == 'a'
    assert pushes[1].push_id == '2'
    assert pushes[1].changeset == 'b'
    assert pushes[2].push_id == '3'
    assert pushes[2].changeset == 'c'

    retry_get.assert_has_calls([
        call('https://hg.mozilla.org/integration/mozilla-inbound/json-pushes'
             '?changeset=fromchset'),
        call().raise_for_status(),
        call().json(),
        call('https://hg.mozilla.org/integration/mozilla-inbound/json-pushes'
             '?fromchange=fromchset&tochange=tochset'),
        call().raise_for_status(),
        call().json()
    ])
Esempio n. 2
0
 def _bisect_integration(self,
                         good_rev,
                         bad_rev,
                         ensure_good_and_bad=False,
                         expand=0):
     LOG.info("Getting %s builds between %s and %s" %
              (self.fetch_config.integration_branch, good_rev, bad_rev))
     handler = IntegrationHandler(find_fix=self.options.find_fix,
                                  ensure_good_and_bad=ensure_good_and_bad)
     result = self._do_bisect(handler, good_rev, bad_rev, expand=expand)
     if result == Bisection.FINISHED:
         LOG.info("No more integration revisions, bisection finished.")
         handler.print_range()
         if handler.good_revision == handler.bad_revision:
             LOG.warning("It seems that you used two changesets that are in"
                         " the same push. Check the pushlog url.")
         elif len(handler.build_range) == 2:
             # range reduced to 2 pushes (at least ones with builds):
             # one good, one bad.
             result = handler.handle_merge()
             if result:
                 branch, good_rev, bad_rev = result
                 self.fetch_config.set_repo(branch)
                 return self._bisect_integration(good_rev,
                                                 bad_rev,
                                                 expand=DEFAULT_EXPAND)
             else:
                 # This code is broken, it prints out the message even when
                 # there are multiple bug numbers or commits in the range.
                 # Somebody should fix it before re-enabling it.
                 return 0
                 # print a bug if:
                 # (1) there really is only one bad push (and we're not
                 # just missing the builds for some intermediate builds)
                 # (2) there is only one bug number in that push
                 jp = JsonPushes(handler.build_range[1].repo_name)
                 num_pushes = len(
                     jp.pushes_within_changes(
                         handler.build_range[0].changeset,
                         handler.build_range[1].changeset))
                 if num_pushes == 2:
                     bugids = find_bugids_in_push(
                         handler.build_range[1].repo_name,
                         handler.build_range[1].changeset)
                     if len(bugids) == 1:
                         word = 'fix' if handler.find_fix else 'regression'
                         LOG.info("Looks like the following bug has the "
                                  " changes which introduced the"
                                  " {}:\n{}".format(word,
                                                    bug_url(bugids[0])))
     elif result == Bisection.USER_EXIT:
         self._print_resume_info(handler)
     else:
         # NO_DATA. With integration branches, this can not happen if changesets
         # are incorrect - so builds are probably too old
         LOG.info(
             'There are no build artifacts for these changesets (they are probably too old).'
         )
         return 1
     return 0
Esempio n. 3
0
def test_pushes_within_changes(mocker):
    push_first = {'1': {'changesets': ['a']}}
    other_pushes = {
        '2': {'changesets': ['b']},
        '3': {'changesets': ['c']}
    }

    retry_get = mocker.patch('mozregression.json_pushes.retry_get')
    response = Mock(json=Mock(side_effect=[push_first, other_pushes]))
    retry_get.return_value = response

    jpushes = JsonPushes()
    pushes = jpushes.pushes_within_changes('fromchset', "tochset")

    assert pushes[0].push_id == '1'
    assert pushes[0].changeset == 'a'
    assert pushes[1].push_id == '2'
    assert pushes[1].changeset == 'b'
    assert pushes[2].push_id == '3'
    assert pushes[2].changeset == 'c'

    retry_get.assert_has_calls([
        call('https://hg.mozilla.org/integration/mozilla-inbound/json-pushes'
             '?changeset=fromchset'),
        call().raise_for_status(),
        call().json(),
        call('https://hg.mozilla.org/integration/mozilla-inbound/json-pushes'
             '?fromchange=fromchset&tochange=tochset'),
        call().raise_for_status(),
        call().json()
    ])
Esempio n. 4
0
 def _bisect_inbounds(self, good_rev, bad_rev, ensure_good_and_bad=False,
                      expand=0):
     LOG.info("Getting %s builds between %s and %s"
              % (self.fetch_config.inbound_branch, good_rev, bad_rev))
     handler = InboundHandler(find_fix=self.options.find_fix,
                              ensure_good_and_bad=ensure_good_and_bad)
     result = self._do_bisect(handler, good_rev, bad_rev, expand=expand)
     if result == Bisection.FINISHED:
         LOG.info("No more inbound revisions, bisection finished.")
         handler.print_range()
         if handler.good_revision == handler.bad_revision:
             LOG.warning(
                 "It seems that you used two changesets that are in"
                 " the same push. Check the pushlog url."
             )
         elif len(handler.build_range) == 2:
             # range reduced to 2 pushes (at least ones with builds):
             # one good, one bad.
             result = handler.handle_merge()
             if result:
                 branch, good_rev, bad_rev = result
                 self.fetch_config.set_repo(branch)
                 return self._bisect_inbounds(good_rev, bad_rev,
                                              expand=DEFAULT_EXPAND)
             else:
                 # This code is broken, it prints out the message even when
                 # there are multiple bug numbers or commits in the range.
                 # Somebody should fix it before re-enabling it.
                 return 0
                 # print a bug if:
                 # (1) there really is only one bad push (and we're not
                 # just missing the builds for some intermediate builds)
                 # (2) there is only one bug number in that push
                 jp = JsonPushes(handler.build_range[1].repo_name)
                 num_pushes = len(jp.pushes_within_changes(
                     handler.build_range[0].changeset,
                     handler.build_range[1].changeset))
                 if num_pushes == 2:
                     bugids = find_bugids_in_push(
                         handler.build_range[1].repo_name,
                         handler.build_range[1].changeset
                     )
                     if len(bugids) == 1:
                         word = 'fix' if handler.find_fix else 'regression'
                         LOG.info("Looks like the following bug has the "
                                  " changes which introduced the"
                                  " {}:\n{}".format(word,
                                                    bug_url(bugids[0])))
     elif result == Bisection.USER_EXIT:
         self._print_resume_info(handler)
     else:
         # NO_DATA. With inbounds, this can not happen if changesets
         # are incorrect - so builds are probably too old
         LOG.info(
             'There are no build artifacts on inbound for these'
             ' changesets (they are probably too old).')
         return 1
     return 0
Esempio n. 5
0
    def handle_merge(self):
        # let's check if we are facing a merge, and in that case,
        # continue the bisection from the merged branch.
        result = None

        LOG.debug("Starting merge handling...")
        # we have to check the commit of the most recent push
        most_recent_push = self.build_range[1]
        jp = JsonPushes(most_recent_push.repo_name)
        push = jp.push(most_recent_push.changeset, full='1')
        msg = push.changeset['desc']
        LOG.debug("Found commit message:\n%s\n" % msg)
        branch = find_branch_in_merge_commit(msg)
        if not (branch and len(push.changesets) >= 2):
            return
        try:
            # so, this is a merge. We can find the oldest and youngest
            # changesets, and the branch where the merge comes from.
            oldest = push.changesets[0]['node']
            # exclude the merge commit
            youngest = push.changesets[-2]['node']
            LOG.debug("This is a merge from %s" % branch)

            # we can't use directly the youngest changeset because we
            # don't know yet if it is good.
            #
            # PUSH1    PUSH2
            # [1 2] [3 4 5 6 7]
            #    G    MERGE  B
            #
            # so first, grab it. This needs to be done on the right branch.
            jp2 = JsonPushes(branch)
            raw = [int(p.push_id) for p in
                   jp2.pushes_within_changes(oldest, youngest)]
            data = jp2.pushes(
                startID=str(min(raw) - 2),
                endID=str(max(raw)),
            )

            oldest = data[0].changesets[0]
            youngest = data[-1].changesets[-1]

            # we are ready to bisect further
            LOG.info("************* Switching to %s" % branch)
            gr, br = self._reverse_if_find_fix(oldest, youngest)
            result = (branch, gr, br)
        except MozRegressionError:
            LOG.debug("Got exception", exc_info=True)
            raise MozRegressionError(
                "Unable to exploit the merge commit. Origin branch is {}, and"
                " the commit message for {} was:\n{}".format(
                    most_recent_push.repo_name,
                    most_recent_push.short_changeset,
                    msg
                )
            )
        LOG.debug('End merge handling')
        return result
Esempio n. 6
0
    def handle_merge(self):
        # let's check if we are facing a merge, and in that case,
        # continue the bisection from the merged branch.
        result = None

        LOG.debug("Starting merge handling...")
        # we have to check the commit of the most recent push
        most_recent_push = self.build_range[1]
        jp = JsonPushes(most_recent_push.repo_name)
        push = jp.push(most_recent_push.changeset, full='1')
        msg = push.changeset['desc']
        LOG.debug("Found commit message:\n%s\n" % msg)
        branch = find_branch_in_merge_commit(msg)
        if not (branch and len(push.changesets) >= 2):
            return
        try:
            # so, this is a merge. We can find the oldest and youngest
            # changesets, and the branch where the merge comes from.
            oldest = push.changesets[0]['node']
            # exclude the merge commit
            youngest = push.changesets[-2]['node']
            LOG.debug("This is a merge from %s" % branch)

            # we can't use directly the youngest changeset because we
            # don't know yet if it is good.
            #
            # PUSH1    PUSH2
            # [1 2] [3 4 5 6 7]
            #    G    MERGE  B
            #
            # so first, grab it. This needs to be done on the right branch.
            jp2 = JsonPushes(branch)
            raw = [int(p.push_id) for p in
                   jp2.pushes_within_changes(oldest, youngest)]
            data = jp2.pushes(
                startID=str(min(raw) - 2),
                endID=str(max(raw)),
            )

            oldest = data[0].changesets[0]
            youngest = data[-1].changesets[-1]

            # we are ready to bisect further
            LOG.info("************* Switching to %s" % branch)
            gr, br = self._reverse_if_find_fix(oldest, youngest)
            result = (branch, gr, br)
        except MozRegressionError:
            LOG.debug("Got exception", exc_info=True)
            raise MozRegressionError(
                "Unable to exploit the merge commit. Origin branch is {}, and"
                " the commit message for {} was:\n{}".format(
                    most_recent_push.repo_name,
                    most_recent_push.short_changeset,
                    msg
                )
            )
        LOG.debug('End merge handling')
        return result
Esempio n. 7
0
def test_push_with_date_raise_appropriate_error():
    jpushes = JsonPushes(branch='inbound')
    jpushes.pushes_within_changes = Mock(side_effect=EmptyPushlogError)

    with pytest.raises(EmptyPushlogError) as ctx:
        jpushes.push(date(2015, 1, 1))

    assert str(ctx.value) == \
        'No pushes available for the date 2015-01-01 on inbound.'
Esempio n. 8
0
def test_push_with_date_raise_appropriate_error():
    jpushes = JsonPushes(branch='inbound')
    jpushes.pushes_within_changes = Mock(side_effect=EmptyPushlogError)

    with pytest.raises(EmptyPushlogError) as ctx:
        jpushes.push(date(2015, 1, 1))

    assert str(ctx.value) == \
        'No pushes available for the date 2015-01-01 on inbound.'
Esempio n. 9
0
def test_pushes_within_changes_using_dates(mocker):
    p1 = {'changesets': ['abc'], 'date': 12345}
    p2 = {'changesets': ['def'], 'date': 67891}
    pushes = {'1': p1, '2': p2}

    retry_get = mocker.patch('mozregression.json_pushes.retry_get')
    retry_get.return_value = Mock(json=Mock(return_value=pushes))

    jpushes = JsonPushes(branch='m-i')

    pushes = jpushes.pushes_within_changes(date(2015, 1, 1), date(2015, 2, 2))
    assert pushes[0].push_id == '1'
    assert pushes[1].push_id == '2'

    retry_get.assert_called_once_with(
        'https://hg.mozilla.org/integration/mozilla-inbound/json-pushes?'
        'enddate=2015-02-03&startdate=2015-01-01')
Esempio n. 10
0
def test_pushes_within_changes_using_dates(mocker):
    p1 = {"changesets": ["abc"], "date": 12345}
    p2 = {"changesets": ["def"], "date": 67891}
    pushes = {"1": p1, "2": p2}

    retry_get = mocker.patch("mozregression.json_pushes.retry_get")
    retry_get.return_value = Mock(json=Mock(return_value=pushes))

    jpushes = JsonPushes(branch="m-i")

    pushes = jpushes.pushes_within_changes(date(2015, 1, 1), date(2015, 2, 2))
    assert pushes[0].push_id == "1"
    assert pushes[1].push_id == "2"

    retry_get.assert_called_once_with(
        "https://hg.mozilla.org/integration/mozilla-inbound/json-pushes?"
        "enddate=2015-02-03&startdate=2015-01-01")
Esempio n. 11
0
def test_pushes_within_changes_using_dates(mocker):
    p1 = {'changesets': ['abc'], 'date': 12345}
    p2 = {'changesets': ['def'], 'date': 67891}
    pushes = {'1': p1, '2': p2}

    retry_get = mocker.patch('mozregression.json_pushes.retry_get')
    retry_get.return_value = Mock(json=Mock(return_value=pushes))

    jpushes = JsonPushes(branch='m-i')

    pushes = jpushes.pushes_within_changes(date(2015, 1, 1), date(2015, 2, 2))
    assert pushes[0].push_id == '1'
    assert pushes[1].push_id == '2'

    retry_get.assert_called_once_with(
        'https://hg.mozilla.org/integration/mozilla-inbound/json-pushes?'
        'startdate=2015-01-01&enddate=2015-02-03'
    )
Esempio n. 12
0
    def handle_merge(self):
        # let's check if we are facing a merge, and in that case,
        # continue the bisection from the merged branch.
        result = None

        LOG.debug("Starting merge handling...")
        # we have to check the commit of the most recent push
        most_recent_push = self.build_range[1]
        jp = JsonPushes(most_recent_push.repo_name)
        push = jp.push(most_recent_push.changeset, full='1')
        msg = push.changeset['desc']
        LOG.debug("Found commit message:\n%s\n" % msg)
        branch = find_branch_in_merge_commit(msg, most_recent_push.repo_name)
        if not (branch and len(push.changesets) >= 2):
            # We did not find a branch, lets check the integration branches if we are bisecting m-c
            LOG.debug(
                "Did not find a branch, checking all integration branches")
            if get_name(most_recent_push.repo_name) == 'mozilla-central' and \
               len(push.changesets) >= 2:
                branch = self._choose_integration_branch(
                    most_recent_push.changeset)
                jp2 = JsonPushes(branch)
                try:
                    data = jp2.pushes_within_changes(
                        push.changesets[0]['node'],
                        push.changesets[-1]['node'])
                except MozRegressionError, exc:
                    LOG.error(
                        "Failed to find changes in branch '%s' (error: %s)" %
                        (branch, exc))
                    raise
                LOG.info("************* Switching to %s by"
                         " process of elimination (no branch detected in"
                         " commit message)" % branch)
                gr, br = self._reverse_if_find_fix(data[0].changeset,
                                                   data[-1].changeset)
                return (branch, gr, br)
            else:
                return
Esempio n. 13
0
def test_pushes_within_changes(mocker):
    push_first = {"1": {"changesets": ["a"]}}
    other_pushes = {"2": {"changesets": ["b"]}, "3": {"changesets": ["c"]}}

    retry_get = mocker.patch("mozregression.json_pushes.retry_get")
    response = Mock(json=Mock(side_effect=[push_first, other_pushes]))
    retry_get.return_value = response

    jpushes = JsonPushes()
    pushes = jpushes.pushes_within_changes("fromchset", "tochset")

    assert pushes[0].push_id == "1"
    assert pushes[0].changeset == "a"
    assert pushes[1].push_id == "2"
    assert pushes[1].changeset == "b"
    assert pushes[2].push_id == "3"
    assert pushes[2].changeset == "c"

    retry_get.assert_has_calls([
        call("https://hg.mozilla.org/mozilla-central/json-pushes"
             "?changeset=fromchset"),
        call("https://hg.mozilla.org/mozilla-central/json-pushes"
             "?fromchange=fromchset&tochange=tochset"),
    ])
Esempio n. 14
0
    def handle_merge(self):
        # let's check if we are facing a merge, and in that case,
        # continue the bisection from the merged branch.
        result = None

        LOG.debug("Starting merge handling...")
        # we have to check the commit of the most recent push
        most_recent_push = self.build_range[1]
        jp = JsonPushes(most_recent_push.repo_name)
        push = jp.push(most_recent_push.changeset, full='1')
        msg = push.changeset['desc']
        LOG.debug("Found commit message:\n%s\n" % msg)
        branch = find_branch_in_merge_commit(msg, most_recent_push.repo_name)
        if not (branch and len(push.changesets) >= 2):
            # We did not find a branch, lets check the integration branches if we are bisecting m-c
            LOG.debug(
                "Did not find a branch, checking all integration branches")
            if get_name(most_recent_push.repo_name) == 'mozilla-central' and \
               len(push.changesets) >= 2:
                branch = self._choose_integration_branch(
                    most_recent_push.changeset)
                oldest = push.changesets[0]['node']
                youngest = push.changesets[-1]['node']
                LOG.info("************* Switching to %s by"
                         " process of elimination (no branch detected in"
                         " commit message)" % branch)
            else:
                return
        else:
            # so, this is a merge. see how many changesets are in it, if it
            # is just one, we have our answer
            if len(push.changesets) == 2:
                LOG.info("Merge commit has only two revisions (one of which "
                         "is the merge): we are done")
                return

            # Otherwise, we can find the oldest and youngest
            # changesets, and the branch where the merge comes from.
            oldest = push.changesets[0]['node']
            # exclude the merge commit
            youngest = push.changesets[-2]['node']
            LOG.info("************* Switching to %s" % branch)

        # we can't use directly the oldest changeset because we
        # don't know yet if it is good.
        #
        # PUSH1    PUSH2
        # [1 2] [3 4 5 6 7]
        #    G    MERGE  B
        #
        # so first grab the previous push to get the last known good
        # changeset. This needs to be done on the right branch.
        try:
            jp2 = JsonPushes(branch)
            raw = [
                int(p.push_id)
                for p in jp2.pushes_within_changes(oldest, youngest)
            ]
            data = jp2.pushes(
                startID=str(min(raw) - 2),
                endID=str(max(raw)),
            )

            older = data[0].changeset
            youngest = data[-1].changeset

            # we are ready to bisect further
            gr, br = self._reverse_if_find_fix(older, youngest)
            result = (branch, gr, br)
        except MozRegressionError:
            LOG.debug("Got exception", exc_info=True)
            raise MozRegressionError(
                "Unable to exploit the merge commit. Origin branch is {}, and"
                " the commit message for {} was:\n{}".format(
                    most_recent_push.repo_name,
                    most_recent_push.short_changeset, msg))
        LOG.debug('End merge handling')
        return result
Esempio n. 15
0
    def handle_merge(self):
        # let's check if we are facing a merge, and in that case,
        # continue the bisection from the merged branch.
        result = None

        LOG.debug("Starting merge handling...")
        # we have to check the commit of the most recent push
        most_recent_push = self.build_range[1]
        jp = JsonPushes(most_recent_push.repo_name)
        push = jp.push(most_recent_push.changeset, full='1')
        msg = push.changeset['desc']
        LOG.debug("Found commit message:\n%s\n" % msg)
        branch = find_branch_in_merge_commit(msg, most_recent_push.repo_name)
        if not (branch and len(push.changesets) >= 2):
            # We did not find a branch, lets check the integration branches if we are bisecting m-c
            LOG.debug("Did not find a branch, checking all integration branches")
            if get_name(most_recent_push.repo_name) == 'mozilla-central' and \
               len(push.changesets) >= 2:
                branch = self._choose_integration_branch(most_recent_push.changeset)
                oldest = push.changesets[0]['node']
                youngest = push.changesets[-1]['node']
                LOG.info("************* Switching to %s by"
                         " process of elimination (no branch detected in"
                         " commit message)" % branch)
            else:
                return
        else:
            # so, this is a merge. see how many changesets are in it, if it
            # is just one, we have our answer
            if len(push.changesets) == 2:
                LOG.info("Merge commit has only two revisions (one of which "
                         "is the merge): we are done")
                return

            # Otherwise, we can find the oldest and youngest
            # changesets, and the branch where the merge comes from.
            oldest = push.changesets[0]['node']
            # exclude the merge commit
            youngest = push.changesets[-2]['node']
            LOG.info("************* Switching to %s" % branch)

        # we can't use directly the oldest changeset because we
        # don't know yet if it is good.
        #
        # PUSH1    PUSH2
        # [1 2] [3 4 5 6 7]
        #    G    MERGE  B
        #
        # so first grab the previous push to get the last known good
        # changeset. This needs to be done on the right branch.
        try:
            jp2 = JsonPushes(branch)
            raw = [int(p.push_id) for p in
                   jp2.pushes_within_changes(oldest, youngest)]
            data = jp2.pushes(
                startID=str(min(raw) - 2),
                endID=str(max(raw)),
            )

            older = data[0].changeset
            youngest = data[-1].changeset

            # we are ready to bisect further
            gr, br = self._reverse_if_find_fix(older, youngest)
            result = (branch, gr, br)
        except MozRegressionError:
            LOG.debug("Got exception", exc_info=True)
            raise MozRegressionError(
                "Unable to exploit the merge commit. Origin branch is {}, and"
                " the commit message for {} was:\n{}".format(
                    most_recent_push.repo_name,
                    most_recent_push.short_changeset,
                    msg
                )
            )
        LOG.debug('End merge handling')
        return result