def hide_orphaned_commit_comments(self, pull: PullRequest) -> None: # rewriting history of branch removes commits # we do not want to show test results for those commits anymore # get commits of this pull request commit_shas = set([commit.sha for commit in pull.get_commits()]) # get comments of this pull request comments = self.get_pull_request_comments(pull, order_by_updated=False) # get all comments that come from this action and are not hidden comments = self.get_action_comments(comments) # get comment node ids and their commit sha (possibly abbreviated) matches = [(comment.get('id'), re.search(r'^[Rr]esults for commit ([0-9a-f]{8,40})\.(?:\s.*)?$', comment.get('body'), re.MULTILINE)) for comment in comments] comment_commits = [(node_id, match.group(1)) for node_id, match in matches if match is not None] # get those comment node ids whose commit is not part of this pull request any more comment_ids = [(node_id, comment_commit_sha) for (node_id, comment_commit_sha) in comment_commits if not any([sha for sha in commit_shas if sha.startswith(comment_commit_sha)])] # hide all those comments for node_id, comment_commit_sha in comment_ids: logger.info(f'hiding unit test result comment for commit {comment_commit_sha}') self.hide_comment(node_id)
def publish_comment(self, title: str, stats: UnitTestRunResults, pull_request: PullRequest, check_run: Optional[CheckRun] = None, cases: Optional[UnitTestCaseResults] = None) -> PullRequest: # compare them with earlier stats base_check_run = None if self._settings.compare_earlier: base_commit_sha = self.get_base_commit_sha(pull_request) logger.debug(f'comparing against base={base_commit_sha}') base_check_run = self.get_check_run(base_commit_sha) base_stats = self.get_stats_from_check_run(base_check_run) if base_check_run is not None else None stats_with_delta = get_stats_delta(stats, base_stats, 'base') if base_stats is not None else stats logger.debug(f'stats with delta: {stats_with_delta}') # gather test lists from check run and cases before_all_tests, before_skipped_tests = self.get_test_lists_from_check_run(base_check_run) all_tests, skipped_tests = get_all_tests_list(cases), get_skipped_tests_list(cases) test_changes = SomeTestChanges(before_all_tests, all_tests, before_skipped_tests, skipped_tests) details_url = check_run.html_url if check_run else None summary = get_long_summary_md(stats_with_delta, details_url, test_changes, self._settings.test_changes_limit) body = f'## {title}\n{summary}' # reuse existing commend when comment_mode == comment_mode_update # if none exists or comment_mode != comment_mode_update, create new comment if self._settings.comment_mode != comment_mode_update or not self.reuse_comment(pull_request, body): logger.info('creating comment') pull_request.create_issue_comment(body) return pull_request
def publish(self, stats: UnitTestRunResults, cases: UnitTestCaseResults, conclusion: str): logger.info( f'publishing {conclusion} results for commit {self._settings.commit}' ) check_run = self.publish_check(stats, cases, conclusion) if self._settings.comment_mode != comment_mode_off: pull = self.get_pull(self._settings.commit) if pull is not None: self.publish_comment(self._settings.comment_title, stats, pull, check_run, cases) if self._settings.hide_comment_mode == hide_comments_mode_orphaned: self.hide_orphaned_commit_comments(pull) elif self._settings.hide_comment_mode == hide_comments_mode_all_but_latest: self.hide_all_but_latest_comments(pull) else: logger.info( 'hide_comments disabled, not hiding any comments') else: logger.info( f'there is no pull request for commit {self._settings.commit}' ) else: logger.info( 'comment_on_pr disabled, not commenting on any pull requests')
def hide_all_but_latest_comments(self, pull: PullRequest) -> None: # we want to reduce the number of shown comments to a minimum # get comments of this pull request comments = self.get_pull_request_comments(pull, order_by_updated=False) # get all comments that come from this action and are not hidden comments = self.get_action_comments(comments) # take all but the last comment comment_ids = [comment.get('id') for comment in comments[:-1]] # hide all those comments for node_id in comment_ids: logger.info(f'hiding unit test result comment {node_id}') self.hide_comment(node_id)
def publish_check(self, stats: UnitTestRunResults, cases: UnitTestCaseResults, compare_earlier: bool, conclusion: str) -> CheckRun: # get stats from earlier commits before_stats = None if compare_earlier: before_commit_sha = self._settings.event.get('before') logger.debug(f'comparing against before={before_commit_sha}') before_stats = self.get_stats_from_commit(before_commit_sha) stats_with_delta = get_stats_delta( stats, before_stats, 'earlier') if before_stats is not None else stats logger.debug(f'stats with delta: {stats_with_delta}') error_annotations = get_error_annotations(stats.errors) case_annotations = get_case_annotations( cases, self._settings.report_individual_runs) file_list_annotations = self.get_test_list_annotations(cases) all_annotations = error_annotations + case_annotations + file_list_annotations # we can send only 50 annotations at once, so we split them into chunks of 50 check_run = None all_annotations = [ all_annotations[x:x + 50] for x in range(0, len(all_annotations), 50) ] or [[]] for annotations in all_annotations: output = dict(title=get_short_summary(stats), summary=get_long_summary_with_digest_md( stats_with_delta, stats), annotations=[ annotation.to_dict() for annotation in annotations ]) logger.info('creating check') check_run = self._repo.create_check_run( name=self._settings.check_name, head_sha=self._settings.commit, status='completed', conclusion=conclusion, output=output) logger.debug(f'created check {check_run}') return check_run
def reuse_comment(self, pull: PullRequest, body: str) -> bool: # get comments of this pull request comments = self.get_pull_request_comments(pull, order_by_updated=True) # get all comments that come from this action and are not hidden comments = self.get_action_comments(comments) # if there is no such comment, stop here if len(comments) == 0: return False # edit last comment comment_id = comments[-1].get("databaseId") logger.info(f'editing comment {comment_id}') if ':recycle:' not in body: body = f'{body}\n:recycle: This comment has been updated with latest results.' try: pull.get_issue_comment(comment_id).edit(body) except Exception as e: self._gha.warning(f'Failed to edit existing comment #{comment_id}') logger.debug('editing existing comment failed', exc_info=e) return True