Skip to content

Commit

Permalink
Merge pull request #188 from MartinBernstorff/v3
Browse files Browse the repository at this point in the history
  • Loading branch information
ewjoachim authored Jun 16, 2023
2 parents b3be590 + 41afb91 commit 8044f31
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 86 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
.DS_Store
.coverage
dev-env-vars
*.pyc
.venv
.vscode/settings.json
10 changes: 6 additions & 4 deletions coverage_comment/annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
MISSING_LINES_GROUP_TITLE = "Annotations of lines with missing coverage"


def create_pr_annotations(annotation_type: str, coverage: coverage_module.Coverage):
def create_pr_annotations(annotation_type: str, coverage: coverage_module.DiffCoverage):
github.send_workflow_command(
command="group", command_value=MISSING_LINES_GROUP_TITLE
)

for filename, file_coverage in coverage.files.items():
for missing_line in file_coverage.missing_lines:
for filepath, file_coverage in coverage.files.items():
for missing_line in file_coverage.violation_lines:
github.create_missing_coverage_annotation(
annotation_type=annotation_type, file=filename, line=missing_line
annotation_type=annotation_type,
file=str(filepath),
line=missing_line,
)

github.send_workflow_command(command="endgroup", command_value="")
9 changes: 6 additions & 3 deletions coverage_comment/coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class DiffCoverage:
total_num_violations: int
total_percent_covered: decimal.Decimal
num_changed_lines: int
files: dict[pathlib.Path, FileDiffCoverage]
files: dict[str, FileDiffCoverage]


def compute_coverage(num_covered: int, num_total: int) -> decimal.Decimal:
Expand Down Expand Up @@ -191,14 +191,17 @@ def extract_info(data) -> Coverage:
)


def get_diff_coverage_info(base_ref: str) -> DiffCoverage:
def get_diff_coverage_info(
base_ref: str, compare_to_origin: bool = True
) -> DiffCoverage:
subprocess.run("git", "fetch", "--depth=1000")
subprocess.run("coverage", "xml")
with tempfile.NamedTemporaryFile("r") as f:
ref_prefix = "origin/" if compare_to_origin else ""
subprocess.run(
"diff-cover",
"coverage.xml",
f"--compare-branch=origin/{base_ref}",
f"--compare-branch={ref_prefix}{base_ref}",
f"--json-report={f.name}",
"--diff-range-notation=..",
"--quiet",
Expand Down
13 changes: 9 additions & 4 deletions coverage_comment/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,22 @@ def action(

if event_name in {"pull_request", "push"}:
coverage = coverage_module.get_coverage_info(merge=config.MERGE_COVERAGE_FILES)

if event_name == "pull_request":
diff_coverage = coverage_module.get_diff_coverage_info(
base_ref=config.GITHUB_BASE_REF,
compare_to_origin=config.COV_DIFF_TO_ORIGIN,
)

if config.ANNOTATE_MISSING_LINES:
annotations.create_pr_annotations(
annotation_type=config.ANNOTATION_TYPE, coverage=coverage
annotation_type=config.ANNOTATION_TYPE, coverage=diff_coverage
)

return generate_comment(
config=config,
coverage=coverage,
diff_coverage=diff_coverage,
github_session=github_session,
)
else:
Expand All @@ -105,15 +112,13 @@ def action(
def generate_comment(
config: settings.Config,
coverage: coverage_module.Coverage,
diff_coverage: coverage_module.DiffCoverage,
github_session: httpx.Client,
) -> int:
log.info("Generating comment for PR")

gh = github_client.GitHub(session=github_session)

diff_coverage = coverage_module.get_diff_coverage_info(
base_ref=config.GITHUB_BASE_REF
)
previous_coverage_data_file = storage.get_datafile_contents(
github=gh,
repository=config.GITHUB_REPOSITORY,
Expand Down
1 change: 1 addition & 0 deletions coverage_comment/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class Config:
MERGE_COVERAGE_FILES: bool = False
ANNOTATE_MISSING_LINES: bool = False
ANNOTATION_TYPE: str = "warning"
COV_DIFF_TO_ORIGIN: bool = False
VERBOSE: bool = False
# Only for debugging, not exposed in the action:
FORCE_WORKFLOW_RUN: bool = False
Expand Down
94 changes: 34 additions & 60 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io
import os
import zipfile
from collections.abc import Callable

import httpx
import pytest
Expand Down Expand Up @@ -43,7 +44,7 @@ def _(**kwargs):


@pytest.fixture
def pull_request_config(base_config):
def pull_request_config(base_config) -> Callable:
def _(**kwargs):
defaults = {
# GitHub stuff
Expand Down Expand Up @@ -214,65 +215,6 @@ def coverage_obj_no_branch():
)


@pytest.fixture
def coverage_obj_many_missing_lines():
return coverage_module.Coverage(
meta=coverage_module.CoverageMetadata(
version="1.2.3",
timestamp=datetime.datetime(2000, 1, 1),
branch_coverage=True,
show_contexts=False,
),
info=coverage_module.CoverageInfo(
covered_lines=7,
num_statements=10,
percent_covered=decimal.Decimal("0.8"),
missing_lines=12,
excluded_lines=0,
num_branches=2,
num_partial_branches=1,
covered_branches=1,
missing_branches=1,
),
files={
"codebase/main.py": coverage_module.FileCoverage(
path="codebase/main.py",
executed_lines=[1, 2, 5, 6, 9],
missing_lines=[3, 7, 13, 21, 123],
excluded_lines=[],
info=coverage_module.CoverageInfo(
covered_lines=5,
num_statements=10,
percent_covered=decimal.Decimal("0.5"),
missing_lines=5,
excluded_lines=0,
num_branches=2,
num_partial_branches=1,
covered_branches=1,
missing_branches=1,
),
),
"codebase/caller.py": coverage_module.FileCoverage(
path="codebase/caller.py",
executed_lines=[1, 2, 5],
missing_lines=[13, 21, 212],
excluded_lines=[],
info=coverage_module.CoverageInfo(
covered_lines=3,
num_statements=6,
percent_covered=decimal.Decimal("0.5"),
missing_lines=3,
excluded_lines=0,
num_branches=2,
num_partial_branches=1,
covered_branches=1,
missing_branches=1,
),
),
},
)


@pytest.fixture
def diff_coverage_obj():
return coverage_module.DiffCoverage(
Expand All @@ -290,6 +232,38 @@ def diff_coverage_obj():
)


@pytest.fixture
def diff_coverage_obj_many_missing_lines():
return coverage_module.DiffCoverage(
total_num_lines=20,
total_num_violations=1,
total_percent_covered=decimal.Decimal("0.7"),
num_changed_lines=52,
files={
"codebase/code.py": coverage_module.FileDiffCoverage(
path="codebase/code.py",
percent_covered=decimal.Decimal("0.8"),
violation_lines=[3, 5, 21, 111],
),
"codebase/helper.py": coverage_module.FileDiffCoverage(
path="codebase/helper.py",
percent_covered=decimal.Decimal("0.6"),
violation_lines=[19, 22],
),
"codebase/log.py": coverage_module.FileDiffCoverage(
path="codebase/log.py",
percent_covered=decimal.Decimal("0.9"),
violation_lines=[],
),
"codebase/files.py": coverage_module.FileDiffCoverage(
path="codebase/files.py",
percent_covered=decimal.Decimal("0.8"),
violation_lines=[120, 121, 122],
),
},
)


@pytest.fixture
def session(is_failed):
"""
Expand Down
8 changes: 5 additions & 3 deletions tests/integration/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os
import pathlib
import subprocess
from collections.abc import Callable

import pytest

Expand All @@ -28,7 +29,7 @@ def file_path(integration_dir):


@pytest.fixture
def write_file(file_path):
def write_file(file_path) -> Callable:
def _(*variables):
content = "import os"
for i, var in enumerate(variables):
Expand Down Expand Up @@ -255,13 +256,14 @@ def test_action__pull_request__annotations(
)(status_code=200)

result = main.action(
config=pull_request_config(ANNOTATE_MISSING_LINES=True),
config=pull_request_config(
ANNOTATE_MISSING_LINES=True, COV_DIFF_TO_ORIGIN=False
),
github_session=session,
http_session=session,
git=None,
)
expected = """::group::Annotations of lines with missing coverage
::warning file=foo.py,line=6::This line has no coverage
::endgroup::"""
output = capsys.readouterr()

Expand Down
27 changes: 15 additions & 12 deletions tests/unit/test_annotations.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from coverage_comment import annotations


def test_annotations(coverage_obj, capsys):
annotations.create_pr_annotations(annotation_type="warning", coverage=coverage_obj)
def test_annotations(diff_coverage_obj, capsys):
annotations.create_pr_annotations(
annotation_type="warning", coverage=diff_coverage_obj
)

expected = """::group::Annotations of lines with missing coverage
::warning file=codebase/code.py,line=7::This line has no coverage
Expand All @@ -12,20 +14,21 @@ def test_annotations(coverage_obj, capsys):
assert output.out.strip() == expected


def test_annotations_several_files(coverage_obj_many_missing_lines, capsys):
def test_annotations_several_files(diff_coverage_obj_many_missing_lines, capsys):
annotations.create_pr_annotations(
annotation_type="notice", coverage=coverage_obj_many_missing_lines
annotation_type="notice", coverage=diff_coverage_obj_many_missing_lines
)

expected = """::group::Annotations of lines with missing coverage
::notice file=codebase/main.py,line=3::This line has no coverage
::notice file=codebase/main.py,line=7::This line has no coverage
::notice file=codebase/main.py,line=13::This line has no coverage
::notice file=codebase/main.py,line=21::This line has no coverage
::notice file=codebase/main.py,line=123::This line has no coverage
::notice file=codebase/caller.py,line=13::This line has no coverage
::notice file=codebase/caller.py,line=21::This line has no coverage
::notice file=codebase/caller.py,line=212::This line has no coverage
::notice file=codebase/code.py,line=3::This line has no coverage
::notice file=codebase/code.py,line=5::This line has no coverage
::notice file=codebase/code.py,line=21::This line has no coverage
::notice file=codebase/code.py,line=111::This line has no coverage
::notice file=codebase/helper.py,line=19::This line has no coverage
::notice file=codebase/helper.py,line=22::This line has no coverage
::notice file=codebase/files.py,line=120::This line has no coverage
::notice file=codebase/files.py,line=121::This line has no coverage
::notice file=codebase/files.py,line=122::This line has no coverage
::endgroup::"""
output = capsys.readouterr()
assert output.out.strip() == expected

0 comments on commit 8044f31

Please sign in to comment.