Skip to content

Commit

Permalink
Use badges to display basic coverage information in coverage comment
Browse files Browse the repository at this point in the history
  • Loading branch information
kieferro committed Aug 30, 2023
1 parent 0ee7375 commit 39ae4ea
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 66 deletions.
18 changes: 18 additions & 0 deletions coverage_comment/badge.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ def get_badge_color(
return "red"


def get_evolution_badge_color(
rate_before: decimal.Decimal | None,
rate_after: decimal.Decimal,
) -> str:
if rate_before is None or rate_after > rate_before:
return "brightgreen"
elif rate_after == rate_before:
return "blue"
else:
return "orange"


def compute_badge_endpoint_data(
line_rate: decimal.Decimal,
color: str,
Expand Down Expand Up @@ -52,6 +64,12 @@ def compute_badge_image(
).text


def get_static_badge_url(label: str, message: str, color: str) -> str:
return "https://img.shields.io/badge/" + urllib.parse.quote(
f"{label}-{message}-{color}.svg"
)


def get_endpoint_url(endpoint_url: str) -> str:
return f"https://img.shields.io/endpoint?url={endpoint_url}"

Expand Down
2 changes: 2 additions & 0 deletions coverage_comment/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ def generate_comment(
coverage=coverage,
diff_coverage=diff_coverage,
previous_coverage_rate=previous_coverage,
minimum_green=config.MINIMUM_GREEN,
minimum_orange=config.MINIMUM_ORANGE,
repo_name=config.GITHUB_REPOSITORY,
pr_number=config.GITHUB_PR_NUMBER,
base_template=template.read_template_file("comment.md.j2"),
Expand Down
10 changes: 10 additions & 0 deletions coverage_comment/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import jinja2
from jinja2.sandbox import SandboxedEnvironment

from coverage_comment import badge
from coverage_comment import coverage as coverage_module

MARKER = (
Expand Down Expand Up @@ -51,6 +52,8 @@ def get_comment_markdown(
coverage: coverage_module.Coverage,
diff_coverage: coverage_module.DiffCoverage,
previous_coverage_rate: decimal.Decimal | None,
minimum_green: decimal.Decimal,
minimum_orange: decimal.Decimal,
repo_name: str,
pr_number: int,
base_template: str,
Expand All @@ -64,6 +67,13 @@ def get_comment_markdown(
env.filters["file_url"] = get_file_url_function(
repo_name=repo_name, pr_number=pr_number
)
env.filters["get_badge_color"] = lambda r: badge.get_badge_color(
decimal.Decimal(r) * decimal.Decimal("100"),
minimum_green=minimum_green,
minimum_orange=minimum_orange,
)
env.filters["get_evolution_color"] = badge.get_evolution_badge_color
env.filters["generate_badge"] = badge.get_static_badge_url

try:
comment = env.get_template("custom" if custom_template else "base").render(
Expand Down
58 changes: 17 additions & 41 deletions coverage_comment/template_files/comment.md.j2
Original file line number Diff line number Diff line change
@@ -1,46 +1,22 @@
{% block title %}## Coverage report{% if subproject_id %} ({{ subproject_id }}){% endif %}{% endblock title %}
{% block coverage_evolution -%}
{% if previous_coverage_rate -%}
{% block coverage_evolution_wording -%}
The coverage rate went from `{{ previous_coverage_rate | pct }}` to `{{ coverage.info.percent_covered | pct }}`{{" "}}
{%- endblock coverage_evolution_wording %}
{%- block emoji_coverage -%}
{%- if previous_coverage_rate | float < coverage.info.percent_covered | float -%}
{%- block emoji_coverage_up -%}:arrow_up:{%- endblock emoji_coverage_up -%}
{%- elif previous_coverage_rate | float > coverage.info.percent_covered | float -%}
{%- block emoji_coverage_down -%}:arrow_down:{%- endblock emoji_coverage_down -%}
{%- else -%}
{%- block emoji_coverage_constant -%}:arrow_right:{%- endblock emoji_coverage_constant -%}
{%- endif %}
{%- endblock emoji_coverage -%}
{%- else -%}
{% block no_comparison_info -%}
> **Note**
> No coverage data of the default branch was found for comparison. A possible reason for this is that the coverage action has not yet run after a push event and the data is therefore not yet initialized.
{%- endblock no_comparison_info %}

{% block coverage_value_wording -%}
The coverage rate is `{{ coverage.info.percent_covered | pct }}`.
{%- endblock coverage_value_wording %}
{%- endif %}
{%- endblock coverage_evolution %}
{% block branch_coverage -%}
{% block coverage_badges -%}
<span>
{% block coverage_evolution_badge -%}
{% set text = "Coverage for the whole project went from " + ("unknown" if previous_coverage_rate == None else previous_coverage_rate | pct) + " to " + coverage.info.percent_covered | pct -%}
<img title="{{ text }}" alt="{{ text }}" src="{{ 'Coverage evolution' | generate_badge(message=('?' if previous_coverage_rate == None else previous_coverage_rate | pct) + ' > ' + coverage.info.percent_covered | pct, color=previous_coverage_rate | get_evolution_color(coverage.info.percent_covered)) }}">
{% endblock coverage_evolution_badge -%}
{% block pr_coverage_badge -%}
{% set text = diff_coverage.total_percent_covered | pct + " of the code lines added by this PR are covered" -%}
<img title="{{ text }}" alt="{{ text }}" src="{{ 'PR Coverage' | generate_badge(message=diff_coverage.total_percent_covered | pct, color=diff_coverage.total_percent_covered | get_badge_color) }}">
{% endblock pr_coverage_badge -%}
{% block branch_coverage_badge -%}
{% if coverage.meta.branch_coverage and coverage.info.num_branches -%}
{% block branch_coverage_wording -%}
The branch rate is `{{ (coverage.info.covered_branches / coverage.info.num_branches) | pct }}`.
{% endblock branch_coverage_wording -%}
{%- endif %}
{% endblock branch_coverage -%}

{%- if diff_coverage.total_num_lines > 0 -%}
{% block diff_coverage_wording -%}
`{{ diff_coverage.total_percent_covered | pct }}` of new lines are covered.
{%- endblock diff_coverage_wording %}
{%- else -%}
{% block diff_coverage_empty_wording -%}
_None of the new lines are part of the tested code. Therefore, there is no coverage data about them._
{%- endblock diff_coverage_empty_wording %}
{%- endif %}
{% set text = "Branch coverage for the whole project on this PR is " + (coverage.info.covered_branches / coverage.info.num_branches) | pct -%}
<img title="{{ text }}. A branch is a possible way to traverse the code. For example, each if statement adds 2 branches to the code." alt="{{ text }}" src="{{ 'Branch Coverage' | generate_badge(message=(coverage.info.covered_branches / coverage.info.num_branches) | pct, color=(coverage.info.covered_branches / coverage.info.num_branches) | get_badge_color) }}">
{% endif -%}
{% endblock branch_coverage_badge -%}
</span>
{%- endblock coverage_badges %}

{% block coverage_by_file -%}
{%if diff_coverage.files -%}
Expand Down
5 changes: 2 additions & 3 deletions tests/end_to_end/test_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ def test_public_repo(
"--jq=.comments[0].body",
fail_value="\n",
)
assert ":arrow_up:" in comment
assert "## Coverage report (my-great-project)" in comment
assert (
"This comment was produced by python-coverage-comment-action (id: my-great-project)"
Expand Down Expand Up @@ -179,7 +178,7 @@ def test_public_repo(
fail_value="\n",
)

assert ":arrow_up:" in ext_comment
assert "-brightgreen.svg" in ext_comment


@pytest.mark.repo_suffix("private")
Expand Down Expand Up @@ -270,7 +269,7 @@ def test_private_repo(
"--jq=.comments[0].body",
fail_value="\n",
)
assert ":arrow_up:" in comment
assert "-brightgreen.svg" in comment

# Let's merge the PR and see if everything works fine
gh_me("pr", "merge", "1", "--merge")
Expand Down
9 changes: 5 additions & 4 deletions tests/integration/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,8 @@ def checker(payload):
comment_file = pathlib.Path("python-coverage-comment-action.txt").read_text()
assert comment == comment_file
assert comment == summary_file.read_text()
assert "No coverage data of the default branch was found for comparison" in comment
assert "The coverage rate is `77.77%`" in comment
assert "`75%` of new lines are covered." in comment
assert "Coverage for the whole project went from unknown to 77.77%" in comment
assert "75% of the code lines added by this PR are covered" in comment
assert (
"### [foo.py](https://github.com/py-cov-action/foobar/pull/2/files#diff-b08fd7a517303ab07cfa211f74d03c1a4c2e64b3b0656d84ff32ecb449b785d2)\n`75%` of new lines are covered (`77.77%` of the complete file)"
in comment
Expand Down Expand Up @@ -202,7 +201,9 @@ def checker(payload):
assert result == 0

assert not pathlib.Path("python-coverage-comment-action.txt").exists()
assert "The coverage rate went from `30%` to `77.77%` :arrow_up:" in comment
assert "Coverage for the whole project went from 30% to 77.77%" in comment
assert comment.count("<img") == 2
assert "Branch coverage for the whole project" not in comment
assert comment == summary_file.read_text()

expected_output = "COMMENT_FILE_WRITTEN=false\n"
Expand Down
24 changes: 24 additions & 0 deletions tests/unit/test_badge.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,23 @@ def test_get_badge_color(rate, expected):
assert color == expected


@pytest.mark.parametrize(
"rate1, rate2, expected",
[
(decimal.Decimal("70"), decimal.Decimal("80"), "brightgreen"),
(None, decimal.Decimal("10"), "brightgreen"),
(decimal.Decimal("85"), decimal.Decimal("85"), "blue"),
(decimal.Decimal("80"), decimal.Decimal("70"), "orange"),
],
)
def test_get_evolution_badge_color(rate1, rate2, expected):
color = badge.get_evolution_badge_color(
rate_before=rate1,
rate_after=rate2,
)
assert color == expected


def test_compute_badge_endpoint_data():
badge_data = badge.compute_badge_endpoint_data(
line_rate=decimal.Decimal("27.42"), color="red"
Expand All @@ -42,6 +59,13 @@ def test_compute_badge_image(session):
assert badge_data == "foo"


def test_get_static_badge_url():
assert (
badge.get_static_badge_url(label="Label", message="100% > 99%", color="green")
== "https://img.shields.io/badge/Label-100%25%20%3E%2099%25-green.svg"
)


def test_get_endpoint_url():
url = badge.get_endpoint_url(endpoint_url="https://foo")
expected = "https://img.shields.io/endpoint?url=https://foo"
Expand Down
51 changes: 33 additions & 18 deletions tests/unit/test_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ def test_get_comment_markdown(coverage_obj, diff_coverage_obj):
coverage=coverage_obj,
diff_coverage=diff_coverage_obj,
previous_coverage_rate=decimal.Decimal("0.92"),
minimum_green=decimal.Decimal("100"),
minimum_orange=decimal.Decimal("70"),
marker="<!-- foo -->",
repo_name="org/repo",
pr_number=1,
Expand Down Expand Up @@ -47,6 +49,8 @@ def test_template(coverage_obj, diff_coverage_obj):
coverage=coverage_obj,
diff_coverage=diff_coverage_obj,
previous_coverage_rate=decimal.Decimal("0.92"),
minimum_green=decimal.Decimal("79"),
minimum_orange=decimal.Decimal("40"),
repo_name="org/repo",
pr_number=5,
base_template=template.read_template_file("comment.md.j2"),
Expand All @@ -57,10 +61,11 @@ def test_template(coverage_obj, diff_coverage_obj):
""",
)
expected = """## Coverage report (foo)
The coverage rate went from `92%` to `75%` :sob:
The branch rate is `50%`.
`80%` of new lines are covered.
<span>
<img title="Coverage for the whole project went from 92% to 75%" alt="Coverage for the whole project went from 92% to 75%" src="https://img.shields.io/badge/Coverage%20evolution-92%25%20%3E%2075%25-orange.svg">
<img title="80% of the code lines added by this PR are covered" alt="80% of the code lines added by this PR are covered" src="https://img.shields.io/badge/PR%20Coverage-80%25-brightgreen.svg">
<img title="Branch coverage for the whole project on this PR is 50%. A branch is a possible way to traverse the code. For example, each if statement adds 2 branches to the code." alt="Branch coverage for the whole project on this PR is 50%" src="https://img.shields.io/badge/Branch%20Coverage-50%25-orange.svg">
</span>
<details>
<summary>Diff Coverage details (click to unfold)</summary>
Expand Down Expand Up @@ -154,16 +159,19 @@ def test_template_full():
coverage=cov,
diff_coverage=diff_cov,
previous_coverage_rate=decimal.Decimal("1.0"),
minimum_green=decimal.Decimal("100"),
minimum_orange=decimal.Decimal("70"),
marker="<!-- foo -->",
repo_name="org/repo",
pr_number=12,
base_template=template.read_template_file("comment.md.j2"),
)
expected = """## Coverage report
The coverage rate went from `100%` to `100%` :arrow_right:
The branch rate is `100%`.
`100%` of new lines are covered.
<span>
<img title="Coverage for the whole project went from 100% to 100%" alt="Coverage for the whole project went from 100% to 100%" src="https://img.shields.io/badge/Coverage%20evolution-100%25%20%3E%20100%25-blue.svg">
<img title="100% of the code lines added by this PR are covered" alt="100% of the code lines added by this PR are covered" src="https://img.shields.io/badge/PR%20Coverage-100%25-brightgreen.svg">
<img title="Branch coverage for the whole project on this PR is 100%. A branch is a possible way to traverse the code. For example, each if statement adds 2 branches to the code." alt="Branch coverage for the whole project on this PR is 100%" src="https://img.shields.io/badge/Branch%20Coverage-100%25-brightgreen.svg">
</span>
<details>
<summary>Diff Coverage details (click to unfold)</summary>
Expand Down Expand Up @@ -193,16 +201,19 @@ def test_template__no_new_lines_with_coverage(coverage_obj):
coverage=coverage_obj,
diff_coverage=diff_cov,
previous_coverage_rate=decimal.Decimal("1.0"),
minimum_green=decimal.Decimal("100"),
minimum_orange=decimal.Decimal("70"),
marker="<!-- foo -->",
repo_name="org/repo",
pr_number=1,
base_template=template.read_template_file("comment.md.j2"),
)
expected = """## Coverage report
The coverage rate went from `100%` to `75%` :arrow_down:
The branch rate is `50%`.
_None of the new lines are part of the tested code. Therefore, there is no coverage data about them._
<span>
<img title="Coverage for the whole project went from 100% to 75%" alt="Coverage for the whole project went from 100% to 75%" src="https://img.shields.io/badge/Coverage%20evolution-100%25%20%3E%2075%25-orange.svg">
<img title="100% of the code lines added by this PR are covered" alt="100% of the code lines added by this PR are covered" src="https://img.shields.io/badge/PR%20Coverage-100%25-brightgreen.svg">
<img title="Branch coverage for the whole project on this PR is 50%. A branch is a possible way to traverse the code. For example, each if statement adds 2 branches to the code." alt="Branch coverage for the whole project on this PR is 50%" src="https://img.shields.io/badge/Branch%20Coverage-50%25-red.svg">
</span>
<!-- foo -->"""
Expand All @@ -214,18 +225,18 @@ def test_template__no_branch_no_previous(coverage_obj_no_branch, diff_coverage_o
coverage=coverage_obj_no_branch,
diff_coverage=diff_coverage_obj,
previous_coverage_rate=None,
minimum_green=decimal.Decimal("100"),
minimum_orange=decimal.Decimal("70"),
marker="<!-- foo -->",
repo_name="org/repo",
pr_number=3,
base_template=template.read_template_file("comment.md.j2"),
)
expected = """## Coverage report
> **Note**
> No coverage data of the default branch was found for comparison. A possible reason for this is that the coverage action has not yet run after a push event and the data is therefore not yet initialized.
The coverage rate is `75%`.
`80%` of new lines are covered.
<span>
<img title="Coverage for the whole project went from unknown to 75%" alt="Coverage for the whole project went from unknown to 75%" src="https://img.shields.io/badge/Coverage%20evolution-%3F%20%3E%2075%25-brightgreen.svg">
<img title="80% of the code lines added by this PR are covered" alt="80% of the code lines added by this PR are covered" src="https://img.shields.io/badge/PR%20Coverage-80%25-orange.svg">
</span>
<details>
<summary>Diff Coverage details (click to unfold)</summary>
Expand All @@ -251,6 +262,8 @@ def test_template__no_marker(coverage_obj, diff_coverage_obj):
coverage=coverage_obj,
diff_coverage=diff_coverage_obj,
previous_coverage_rate=decimal.Decimal("0.92"),
minimum_green=decimal.Decimal("100"),
minimum_orange=decimal.Decimal("70"),
repo_name="org/repo",
pr_number=1,
base_template=template.read_template_file("comment.md.j2"),
Expand All @@ -265,6 +278,8 @@ def test_template__broken_template(coverage_obj, diff_coverage_obj):
coverage=coverage_obj,
diff_coverage=diff_coverage_obj,
previous_coverage_rate=decimal.Decimal("0.92"),
minimum_green=decimal.Decimal("100"),
minimum_orange=decimal.Decimal("70"),
repo_name="org/repo",
pr_number=1,
base_template=template.read_template_file("comment.md.j2"),
Expand Down

0 comments on commit 39ae4ea

Please sign in to comment.