Skip to content

feature: skip covered files in the report #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Note: Either `GITHUB_PR_NUMBER` or `GITHUB_REF` is required. `GITHUB_PR_NUMBER`
- `ANNOTATE_MISSING_LINES`: Whether to annotate missing lines in the coverage report. Default is False.
- `ANNOTATION_TYPE`: The type of annotation to use for missing lines. 'notice' or 'warning' or 'error'. Default is 'warning'.
- `MAX_FILES_IN_COMMENT`: The maximum number of files to include in the coverage report comment. Default is 25.
- `SKIP_COVERED_FILES_IN_REPORT`: Skip the files with coverage 100% from the report. Default is True.
- `COMPLETE_PROJECT_REPORT`: Whether to include the complete project coverage report in the comment. Default is False.
- `COVERAGE_REPORT_URL`: URL of the full coverage report to mention in the comment.
- `DEBUG`: Whether to enable debug mode. Default is False.
Expand Down
5 changes: 5 additions & 0 deletions codecov/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class Config:
ANNOTATIONS_OUTPUT_PATH: pathlib.Path | None = None
ANNOTATIONS_DATA_BRANCH: str | None = None
MAX_FILES_IN_COMMENT: int = 25
SKIP_COVERED_FILES_IN_REPORT: bool = True
COMPLETE_PROJECT_REPORT: bool = False
COVERAGE_REPORT_URL: str | None = None
# Only for debugging, not exposed in the action
Expand Down Expand Up @@ -87,6 +88,10 @@ def clean_branch_coverage(cls, value: str) -> bool:
def clean_complete_project_report(cls, value: str) -> bool:
return str_to_bool(value)

@classmethod
def clean_skip_covered_files_in_report(cls, value: str) -> bool:
return str_to_bool(value)

@classmethod
def clean_debug(cls, value: str) -> bool:
return str_to_bool(value)
Expand Down
2 changes: 1 addition & 1 deletion codecov/coverage/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def get_coverage_info(self, coverage_path: pathlib.Path) -> Coverage:

@abstractmethod
def extract_info(self, data: dict) -> Coverage:
raise NotImplementedError
raise NotImplementedError # pragma: no cover

def get_diff_coverage_info( # pylint: disable=too-many-locals
self,
Expand Down
8 changes: 6 additions & 2 deletions codecov/coverage/pytest.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
from __future__ import annotations

import datetime
import decimal
import pathlib

from codecov.coverage.base import BaseCoverage, Coverage, CoverageInfo, CoverageMetadata, FileCoverage


class PytestCoverage(BaseCoverage):
def _convert_to_decimal(self, value: float, precision: int = 2) -> decimal.Decimal:
return decimal.Decimal(str(float(value) / 100)).quantize(decimal.Decimal(10) ** -precision)

def extract_info(self, data: dict) -> Coverage:
"""
{
Expand Down Expand Up @@ -69,7 +73,7 @@ def extract_info(self, data: dict) -> Coverage:
info=CoverageInfo(
covered_lines=file_data['summary']['covered_lines'],
num_statements=file_data['summary']['num_statements'],
percent_covered=file_data['summary']['percent_covered'],
percent_covered=self._convert_to_decimal(file_data['summary']['percent_covered']),
percent_covered_display=file_data['summary']['percent_covered_display'],
missing_lines=file_data['summary']['missing_lines'],
excluded_lines=file_data['summary']['excluded_lines'],
Expand All @@ -84,7 +88,7 @@ def extract_info(self, data: dict) -> Coverage:
info=CoverageInfo(
covered_lines=data['totals']['covered_lines'],
num_statements=data['totals']['num_statements'],
percent_covered=data['totals']['percent_covered'],
percent_covered=self._convert_to_decimal(data['totals']['percent_covered']),
percent_covered_display=data['totals']['percent_covered_display'],
missing_lines=data['totals']['missing_lines'],
excluded_lines=data['totals']['excluded_lines'],
Expand Down
5 changes: 3 additions & 2 deletions codecov/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,16 @@ def _process_pr(self):

log.info('Generating comment for PR #%s', self.github.pr_number)
marker = template.get_marker(marker_id=self.config.SUBPROJECT_ID)
files_info, count_files, changed_files_info = template.select_changed_files(
files_info, count_files = template.select_changed_files(
coverage=self.coverage,
diff_coverage=self.diff_coverage,
max_files=self.config.MAX_FILES_IN_COMMENT,
skip_covered_files_in_report=self.config.SKIP_COVERED_FILES_IN_REPORT,
)
coverage_files_info, count_coverage_files = template.select_files(
coverage=self.coverage,
changed_files_info=changed_files_info,
max_files=self.config.MAX_FILES_IN_COMMENT - count_files, # Truncate the report to MAX_FILES_IN_COMMENT
skip_covered_files_in_report=self.config.SKIP_COVERED_FILES_IN_REPORT,
)
try:
comment = template.get_comment_markdown(
Expand Down
30 changes: 14 additions & 16 deletions codecov/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,11 @@ def get_comment_markdown( # pylint: disable=too-many-arguments,too-many-locals


def select_changed_files(
*,
coverage: Coverage,
diff_coverage: DiffCoverage,
max_files: int | None,
) -> tuple[list[FileInfo], int, list[FileInfo]]:
skip_covered_files_in_report: bool,
) -> tuple[list[FileInfo], int]:
"""
Selects the MAX_FILES files with the most new missing lines sorted by path
These are the files which have been modified in the PR
Expand All @@ -156,44 +156,42 @@ def select_changed_files(
files = []
for path, coverage_file in coverage.files.items():
diff_coverage_file = diff_coverage.files.get(path)
if not (diff_coverage_file and diff_coverage_file.added_statements):
continue

if skip_covered_files_in_report and percentage_value(diff_coverage_file.percent_covered) == 100:
continue

file_info = FileInfo(
path=path,
coverage=coverage_file,
diff=diff_coverage_file,
)
has_diff = bool(diff_coverage_file and diff_coverage_file.added_statements)

if has_diff:
files.append(file_info)
files.append(file_info)

return sort_and_trucate_files(files=files, max_files=max_files), len(files), files
return sort_and_trucate_files(files=files, max_files=max_files), len(files)


def select_files(
*,
coverage: Coverage,
changed_files_info: list[FileInfo],
max_files: int | None,
skip_covered_files_in_report: bool,
) -> tuple[list[FileInfo], int]:
"""
Selects the no of `max_files` files from the whole project coverage
Selects only files which are not in changed files report
Select only files which have statements (not empty files)
Select only files which have lines missing coverage if `skip_covered_files_in_report` is True
"""

files = []
changed_files_path = {file.path for file in changed_files_info}
for path, coverage_file in coverage.files.items():
# Don't show the report for files that have been modified in the PR
# This is gonne be covered in the changed files report
if path in changed_files_path:
continue

# Don't show the report for files that have no statements
if coverage_file.info.num_statements == 0:
continue

if skip_covered_files_in_report and percentage_value(coverage_file.info.percent_covered) == 100:
continue

file_info = FileInfo(path=path, coverage=coverage_file, diff=None)
files.append(file_info)

Expand Down
2 changes: 1 addition & 1 deletion codecov/template_files/comment.md.j2
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{%- block coverage_evolution_badge -%}
{%- if coverage %}
{%- set text = "Coverage of the whole project for this PR is " ~ coverage.info.percent_covered_display ~ "%." -%}
{%- set color = coverage.info.percent_covered | get_badge_color -%}
{%- set color = coverage.info.percent_covered | x100 | get_badge_color -%}
<img title="{{ text }}" src="{{ 'Coverage' | generate_badge(message=coverage.info.percent_covered_display ~ '%', color=color) }}">
{%- endif -%}
{%- endblock coverage_evolution_badge -%}
Expand Down
2 changes: 1 addition & 1 deletion codecov/template_files/macros.md.j2
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
{%- set text = "The coverage rate of " ~ path ~ " is " ~ percent_covered_display ~ "% (" ~ covered_statements_count ~ "/" ~ statements_count ~ ")." -%}
{%- set label = percent_covered_display ~ "%" -%}
{%- set message = "(" ~ covered_statements_count ~ "/" ~ statements_count ~ ")" -%}
{%- set color = percent_covered | get_badge_color -%}
{%- set color = percent_covered | x100 | get_badge_color -%}
<td align="center"><a href="{{ path | file_url(base=base) }}"><img title="{{ text }}" src="{{ label | generate_badge(message=message, color=color) }}"></a></td>
{%- endmacro -%}

Expand Down
2 changes: 1 addition & 1 deletion codecov/template_files/pr.md.j2
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{%- if not files %}

_This PR does not seem to contain any modification to coverable code._
_This PR does not include changes to coverable code or code with missing coverage._
{%- else -%}
<details><summary>Click to see coverage of changed files</summary>
<br>
Expand Down
4 changes: 2 additions & 2 deletions tests/coverage/test_pytest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def test_extract_info(self, coverage_json):
info=CoverageInfo(
covered_lines=6,
num_statements=10,
percent_covered=60.0,
percent_covered=PytestCoverage()._convert_to_decimal(60.0),
percent_covered_display='60%',
missing_lines=4,
excluded_lines=0,
Expand All @@ -40,7 +40,7 @@ def test_extract_info(self, coverage_json):
info=CoverageInfo(
covered_lines=6,
num_statements=10,
percent_covered=60.0,
percent_covered=PytestCoverage()._convert_to_decimal(60.0),
percent_covered_display='60%',
missing_lines=4,
excluded_lines=0,
Expand Down
5 changes: 5 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ def test_config_clean_complete_project_report():
assert value is True


def test_config_clean_skip_covered_files_in_report():
value = config.Config.clean_skip_covered_files_in_report('True')
assert value is True


def test_config_clean_debug():
value = config.Config.clean_debug('False')
assert value is False
Expand Down
7 changes: 6 additions & 1 deletion tests/test_github.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,14 +361,19 @@ def test_post_comment_update(
test_config,
gh_client,
):
comment_with_no_marker = {
'user': {'login': 'foo'},
'body': 'Hey! Hi! How are you?',
'id': 123,
}
comment = {
'user': {'login': 'foo'},
'body': 'Hey! Hi! How are you? marker',
'id': 456,
}
session.register(
'GET', f'/repos/{test_config.GITHUB_REPOSITORY}/issues/{test_config.GITHUB_PR_NUMBER}/comments'
)(json=[comment])
)(json=[comment_with_no_marker, comment])
session.register(
'PATCH',
f'/repos/{test_config.GITHUB_REPOSITORY}/issues/comments/{comment["id"]}',
Expand Down
Loading