Exemple #1
0
    def publish_results(self, payload):
        assert self.publish is True, "Publication disabled"
        mode, build, extras = payload
        logger.debug("Publishing a Phabricator build update",
                     mode=mode,
                     build=build)

        if mode == "fail:general":
            failure = UnitResult(
                namespace="code-review",
                name="general",
                result=UnitResultState.Broken,
                details=
                "WARNING: An error occurred in the code review bot.\n\n```{}```"
                .format(extras["message"]),
                format="remarkup",
                duration=extras.get("duration", 0),
            )
            self.api.update_build_target(build.target_phid,
                                         BuildState.Fail,
                                         unit=[failure])

        elif mode == "fail:mercurial":
            failure = UnitResult(
                namespace="code-review",
                name="mercurial",
                result=UnitResultState.Fail,
                details=
                "WARNING: The code review bot failed to apply your patch.\n\n```{}```"
                .format(extras["message"]),
                format="remarkup",
                duration=extras.get("duration", 0),
            )
            self.api.update_build_target(build.target_phid,
                                         BuildState.Fail,
                                         unit=[failure])

        elif mode == "success":
            self.api.create_harbormaster_uri(
                build.target_phid,
                "treeherder",
                "Treeherder Jobs",
                extras["treeherder_url"],
            )

        elif mode == "work":
            self.api.update_build_target(build.target_phid, BuildState.Work)
            logger.info("Published public build as working", build=str(build))

        else:
            logger.warning("Unsupported publication", mode=mode, build=build)

        return True
Exemple #2
0
    async def handle_build(self, build_target_phid, diff):
        '''
        Try to load and apply a diff on local clone
        If succesful, push to try and send a treeherder link
        If failure, send a unit result with a warning message
        '''
        failure = None
        start = time.time()
        try:
            await self.push_to_try(build_target_phid, diff)
        except hglib.error.CommandError as e:
            # Format nicely the error log
            error_log = e.err
            if isinstance(error_log, bytes):
                error_log = error_log.decode('utf-8')

            logger.warn('Mercurial error on diff', error=error_log, args=e.args, phid=diff['phid'])

            # Report mercurial failure as a Unit Test issue
            failure = UnitResult(
                namespace='code-review',
                name='mercurial',
                result=UnitResultState.Fail,
                details='WARNING: The code review bot failed to apply your patch.\n\n```{}```'.format(error_log),
                format='remarkup',
                duration=time.time() - start,
            )

        except Exception as e:
            logger.warn('Failed to process diff', error=e, phid=diff['phid'])

            # Report generic failure as a Unit Test issue
            failure = UnitResult(
                namespace='code-review',
                name='general',
                result=UnitResultState.Broken,
                details='WARNING: An error occured in the code review bot.\n\n```{}```'.format(e),
                format='remarkup',
                duration=time.time() - start,
            )

        if failure is not None:
            # Remove uncommited changes
            self.repo.revert(self.repo_dir.encode('utf-8'), all=True)

            # Publish failure
            if self.publish_phabricator:
                self.phabricator_api.update_build_target(build_target_phid, BuildState.Fail, unit=[failure])

            return False

        return True
Exemple #3
0
    def publish_results(self, payload):
        assert self.publish is True, 'Publication disabled'
        mode, build, extras = payload
        logger.debug('Publishing a Phabricator build update',
                     mode=mode,
                     build=build)

        if mode == 'fail:general':
            failure = UnitResult(
                namespace='code-review',
                name='general',
                result=UnitResultState.Broken,
                details=
                'WARNING: An error occured in the code review bot.\n\n```{}```'
                .format(extras['message']),
                format='remarkup',
                duration=extras.get('duration', 0))
            self.api.update_build_target(build.target_phid,
                                         BuildState.Fail,
                                         unit=[failure])

        elif mode == 'fail:mercurial':
            failure = UnitResult(
                namespace='code-review',
                name='mercurial',
                result=UnitResultState.Fail,
                details=
                'WARNING: The code review bot failed to apply your patch.\n\n```{}```'
                .format(extras['message']),
                format='remarkup',
                duration=extras.get('duration', 0))
            self.api.update_build_target(build.target_phid,
                                         BuildState.Fail,
                                         unit=[failure])

        elif mode == 'success':
            self.api.create_harbormaster_uri(build.target_phid, 'treeherder',
                                             'Treeherder Jobs',
                                             extras['treeherder_url'])

        elif mode == 'work':
            self.api.update_build_target(build.target_phid, BuildState.Work)
            logger.info('Published public build as working', build=str(build))

        else:
            logger.warning('Unsupported publication', mode=mode, build=build)

        return True
Exemple #4
0
    def as_phabricator_unitresult(self):
        """
        Build a Phabricator UnitResult for build errors
        """
        assert (self.is_build_error()
                ), "Only build errors may be published as unit results"

        return UnitResult(
            namespace="code-review",
            name="general",
            result=UnitResultState.Fail,
            details=
            f"Code review bot found a **build error**: \n{self.message}",
            format="remarkup",
        )
Exemple #5
0
    def as_phabricator_unitresult(self):
        """
        Output an UnitResult if this is a build error
        """
        if not self.build_error:
            raise Exception(
                "Current issue is not a build error: {}".format(self))

        return UnitResult(
            namespace="code-review",
            name="general",
            result=UnitResultState.Fail,
            details=self.message,
            format="remarkup",
        )
Exemple #6
0
def test_coverity_task(
    mock_config, mock_revision, mock_workflow, mock_backend, mock_hgmo
):
    """
    Test a remote workflow with a clang-tidy analyzer
    """
    from code_review_bot import Reliability
    from code_review_bot.tasks.coverity import CoverityIssue

    mock_workflow.setup_mock_tasks(
        {
            "decision": {
                "image": "taskcluster/decision:XXX",
                "env": {
                    "GECKO_HEAD_REPOSITORY": "https://hg.mozilla.org/try",
                    "GECKO_HEAD_REV": "deadbeef1234",
                },
            },
            "remoteTryTask": {"dependencies": ["coverity"]},
            "coverity": {
                "name": "source-test-coverity-coverity",
                "state": "completed",
                "artifacts": {
                    "public/code-review/coverity.json": {
                        "files": {
                            "test.cpp": {
                                "warnings": [
                                    {
                                        "line": 66,
                                        "flag": "UNINIT",
                                        "reliability": "high",
                                        "message": 'Using uninitialized value "a".',
                                        "extra": {
                                            "category": "Memory - corruptions",
                                            "stateOnServer": {
                                                "presentInReferenceSnapshot": False
                                            },
                                            "stack": [
                                                {
                                                    "line_number": 61,
                                                    "description": 'Condition "!target.oper…", taking false branch.',
                                                    "file_path": "dom/animation/Animation.cpp",
                                                    "path_type": "path",
                                                }
                                            ],
                                        },
                                    }
                                ]
                            },
                            "dom/something.cpp": {
                                "warnings": [
                                    {
                                        "line": 123,
                                        "flag": "UNINIT",
                                        "reliability": "high",
                                        "build_error": True,
                                        "message": "Some error here",
                                        "extra": {
                                            "category": "Nice bug",
                                            "stateOnServer": {
                                                "presentInReferenceSnapshot": False
                                            },
                                            "stack": [
                                                {
                                                    "line_number": 61,
                                                    "description": 'Condition "!target.oper…", taking false branch.',
                                                    "file_path": "dom/animation/Animation.cpp",
                                                    "path_type": "path",
                                                }
                                            ],
                                        },
                                    }
                                ]
                            },
                        }
                    }
                },
            },
        }
    )
    issues = mock_workflow.run(mock_revision)
    assert len(issues) == 2
    issue = issues[0]
    assert isinstance(issue, CoverityIssue)
    assert issue.path == "test.cpp"
    assert issue.line == 66
    assert issue.check == "UNINIT"
    assert issue.reliability == Reliability.High
    assert not issue.build_error
    assert (
        issue.message
        == """Using uninitialized value "a".
The path that leads to this defect is:

- //dom/animation/Animation.cpp:61//:
-- `path: Condition \"!target.oper…", taking false branch.`.\n"""
    )
    assert issue.is_local()
    assert not issue.is_clang_error()
    assert issue.validates()
    assert not issue.is_build_error()

    issue = issues[1]
    assert isinstance(issue, CoverityIssue)
    assert issue.path == "dom/something.cpp"
    assert issue.line == 123
    assert issue.check == "UNINIT"
    assert issue.reliability == Reliability.High
    assert issue.build_error
    assert issue.message == "Some error here"
    assert issue.is_local()
    assert not issue.is_clang_error()
    assert issue.validates()
    assert issue.is_build_error()
    assert (
        issue.as_text()
        == f"Checker reliability is high, meaning that the false positive ratio is low.\nSome error here"
    )
    assert issue.as_phabricator_unitresult() == UnitResult(
        namespace="code-review",
        name="general",
        result=UnitResultState.Fail,
        details=f"Code review bot found a **build error**: \n{issue.message}",
        format="remarkup",
    )
    assert check_stats(
        [
            ("code-review.analysis.files", None, 2),
            ("code-review.analysis.lines", None, 2),
            ("code-review.issues", "source-test-coverity-coverity", 2),
            ("code-review.issues.publishable", "source-test-coverity-coverity", 0),
            ("code-review.issues.paths", "source-test-coverity-coverity", 2),
            ("code-review.analysis.issues.publishable", None, 0),
            ("code-review.runtime.reports", None, "runtime"),
        ]
    )
    async def handle_build(self, repository, build):
        '''
        Try to load and apply a diff on local clone
        If successful, push to try and send a treeherder link
        If failure, send a unit result with a warning message
        '''
        assert isinstance(repository, Repository)
        failure = None
        start = time.time()

        try:
            # Start by cleaning the repo
            repository.clean()

            # Get the stack of patches
            base, patches = self.phabricator_api.load_patches_stack(
                repository.repo,
                build.diff,
                default_revision=repository.default_revision,
            )
            assert len(patches) > 0, 'No patches to apply'

            # Load all the diffs details with commits messages
            diffs = self.phabricator_api.search_diffs(
                diff_phid=[p[0] for p in patches],
                attachments={
                    'commits': True,
                }
            )
            commits = {
                diff['phid']: diff['attachments']['commits'].get('commits', [])
                for diff in diffs
            }

            await asyncio.sleep(0)  # allow other tasks to run

            # First apply patches on local repo
            await repository.apply_patches(patches, commits)

            # Configure the try task
            repository.add_try_commit(build)

            # Then push that stack on try
            tip = await repository.push_to_try()
            logger.info('Diff has been pushed !')

            # Publish Treeherder link
            if build.target_phid and self.publish_phabricator:
                uri = TREEHERDER_URL.format(repository.try_name, tip.node.decode('utf-8'))
                self.phabricator_api.create_harbormaster_uri(build.target_phid, 'treeherder', 'Treeherder Jobs', uri)
        except hglib.error.CommandError as e:
            # Format nicely the error log
            error_log = e.err
            if isinstance(error_log, bytes):
                error_log = error_log.decode('utf-8')

            logger.warn('Mercurial error on diff', error=error_log, args=e.args, build=build)

            # Report mercurial failure as a Unit Test issue
            failure = UnitResult(
                namespace='code-review',
                name='mercurial',
                result=UnitResultState.Fail,
                details='WARNING: The code review bot failed to apply your patch.\n\n```{}```'.format(error_log),
                format='remarkup',
                duration=time.time() - start,
            )

        except Exception as e:
            logger.warn('Failed to process diff', error=e, build=build)

            # Report generic failure as a Unit Test issue
            failure = UnitResult(
                namespace='code-review',
                name='general',
                result=UnitResultState.Broken,
                details='WARNING: An error occured in the code review bot.\n\n```{}```'.format(e),
                format='remarkup',
                duration=time.time() - start,
            )

        # Publish failure
        if failure is not None and self.publish_phabricator:
            self.phabricator_api.update_build_target(build.target_phid, BuildState.Fail, unit=[failure])
            return False

        return True