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
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
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
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", )
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", )
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