8000 Bundle Analysis: Display comparison for file paths on PR comments by JerrySentry · Pull Request #952 · codecov/worker · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
This repository was archived by the owner on May 5, 2025. It is now read-only.

Bundle Analysis: Display comparison for file paths on PR comments #952

Merged
merged 10 commits into from
Dec 17, 2024
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
63 changes: 62 additions & 1 deletion services/bundle_analysis/notify/messages/comment.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ class BundleRow(TypedDict):
is_change_outside_threshold: bool


class BundleRouteRow(TypedDict):
route_name: str
change_size_readable: str
percentage_change_readable: str
change_icon: str
route_size: str


class BundleCommentTemplateContext(TypedDict):
pull_url: str
total_size_delta: int
Expand All @@ -42,6 +50,7 @@ class BundleCommentTemplateContext(TypedDict):
status_level: Literal["INFO"] | Literal["WARNING"] | Literal["ERROR"]
warning_threshold_readable: str
bundle_rows: list[BundleRow]
bundle_route_data: dict[str, list[BundleRouteRow]]
has_cached_bundles: bool


Expand Down Expand Up @@ -70,13 +79,17 @@ def build_default_message(
bundle_rows = self._create_bundle_rows(
context.bundle_analysis_comparison, warning_threshold
)
bundle_route_data = self._create_bundle_route_data(
context.bundle_analysis_comparison
)
if warning_threshold.type == "absolute":
warning_threshold_readable = bytes_readable(warning_threshold.threshold)
else:
warning_threshold_readable = str(round(warning_threshold.threshold)) + "%"
context = BundleCommentTemplateContext(
has_cached=any(row["is_cached"] for row in bundle_rows),
bundle_rows=bundle_rows,
bundle_route_data=bundle_route_data,
pull_url=get_bundle_analysis_pull_url(pull=context.pull.database_pull),
total_size_delta=total_size_delta,
status_level=context.commit_status_level.name,
Expand Down Expand Up @@ -159,7 +172,7 @@ def _create_bundle_rows(

change_size = bundle_change.size_delta
if change_size == 0:
# Don't include bundles that were not changes in the table
# Don't include bundles that were not changed in the table
continue
icon = ""
if change_size > 0:
Expand All @@ -184,3 +197,51 @@ def _create_bundle_rows(
)

return bundle_rows

def _create_bundle_route_data(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would we use this computation/stats elsewhere in the code, like in GQL for example? In case it makes sense for this to live in Shared

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, these computations are really for PR comments as it figures out the icons to use and how to display the size (eg bytes, MB, etc). On the app side these are taken care of by gazebo

self,
comparison: BundleAnalysisComparison,
) -> dict[str, list[BundleRouteRow]]:
"""
Translate BundleRouteComparison dict data into a template compatible dict data
"""
bundle_route_data = {}
changes_dict = comparison.bundle_routes_changes()

for bundle_name, route_changes in changes_dict.items():
rows = []
for route_change in route_changes:
change_size, size = (
route_change.size_delta,
bytes_readable(route_change.size_head),
)

if change_size == 0:
continue

if route_change.percentage_delta == 100:
icon = ":rocket:"
bundle_display_name = f"**{route_change.route_name}** _(New)_"
elif route_change.percentage_delta == -100:
icon = ":wastebasket:"
bundle_display_name = (
f"~~**{route_change.route_name}**~~ _(Deleted)_"
)
else:
icon = ""
bundle_display_name = route_change.route_name

rows.append(
BundleRouteRow(
route_name=bundle_display_name,
change_size_readable=bytes_readable(change_size),
percentage_change_readable=f"{route_change.percentage_delta}%",
change_icon=icon,
route_size=size,
)
)

# Only include bundles that have routes
if rows:
bundle_route_data[bundle_name] = rows
return bundle_route_data
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ Bundle size has no change :white_check_mark:
{% if bundle_rows %}{% include "bundle_analysis_notify/bundle_table.md" %}{% if has_cached %}

ℹ️ *Bundle size includes cached data from a previous commit
{%endif%}{% endif %}
{%endif%}{% endif %}
{% if bundle_route_data %}{% include "bundle_analysis_notify/bundle_route_table.md" %}{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{% for bundle_name, routes in bundle_route_data.items %}
<details>
<summary>View changes by path for bundle: {{ bundle_name }}</summary>

| File path | Size | Change |
| --------- | ---- | ------ |{% for bundle_route_row in routes %}
| {{bundle_route_row.route_name}} | {{bundle_route_row.route_size}} | {{bundle_route_row.change_size_readable}} ({{bundle_route_row.percentage_change_readable}}) {{bundle_route_row.change_icon}}{{bundle_route_row.}} |{% endfor %}

</details>
{% endfor %}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ def test_build_message_from_samples(self, dbsession, mocker, mock_storage):
| @codecov/bundler-plugin-core-cjs | 43.32kB | 611 bytes (1.43%) :arrow_up: |
| @codecov/example-next-app-server-cjs | (removed) | 342.32kB (-100.0%) :arrow_down: |

</details>""").format(
</details>
""").format(
pullid=enriched_pull.database_pull.pullid,
owner=head_commit.repository.owner.username,
repo=head_commit.repository.name,
Expand Down
154 changes: 148 additions & 6 deletions services/bundle_analysis/tests/test_bundle_analysis.py
5D32
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from unittest.mock import PropertyMock

import pytest
from shared.bundle_analysis.comparison import BundleChange
from shared.bundle_analysis.comparison import BundleChange, RouteChange
from shared.bundle_analysis.models import AssetType
from shared.bundle_analysis.storage import get_bucket_name
from shared.config import PATCH_CENTRIC_DEFAULT_CONFIG
Expand Down Expand Up @@ -58,7 +58,7 @@ def hook_mock_pull(mocker, mock_pull):


@pytest.mark.parametrize(
"bundle_changes, percent_change, user_config, expected_message",
"bundle_changes, bundle_routes_changes, percent_change, user_config, expected_message",
[
pytest.param(
[
Expand All @@ -81,6 +81,7 @@ def hook_mock_pull(mocker, mock_pull):
percentage_delta=-1.23,
),
],
{},
5.56,
{
**PATCH_CENTRIC_DEFAULT_CONFIG,
Expand All @@ -98,7 +99,8 @@ def hook_mock_pull(mocker, mock_pull):
| ----------- | ---- | ------ |
| added-bundle | 123.46kB | 12.35kB (5.56%) :arrow_up::warning: |
| changed-bundle | 123.46kB | 3.46kB (0.35%) :arrow_up: |
| removed-bundle | (removed) | 1.23kB (-1.23%) :arrow_down: |"""),
| removed-bundle | (removed) | 1.23kB (-1.23%) :arrow_down: |
"""),
id="comment_increase_size_warning",
),
pytest.param(
Expand All @@ -122,6 +124,7 @@ def hook_mock_pull(mocker, mock_pull):
percentage_delta=-100.0,
),
],
{},
5.56,
{
**PATCH_CENTRIC_DEFAULT_CONFIG,
Expand All @@ -139,7 +142,8 @@ def hook_mock_pull(mocker, mock_pull):
| ----------- | ---- | ------ |
| added-bundle | 123.46kB | 12.35kB (5.56%) :arrow_up::x: |
| changed-bundle | 123.46kB | 3.46kB (2.56%) :arrow_up: |
| removed-bundle | (removed) | 1.23kB (-100.0%) :arrow_down: |"""),
| removed-bundle | (removed) | 1.23kB (-100.0%) :arrow_down: |
"""),
id="comment_increase_size_error",
),
pytest.param(
Expand All @@ -163,6 +167,7 @@ def hook_mock_pull(mocker, mock_pull):
percentage_delta=2.56,
),
],
{},
3.46,
{
**PATCH_CENTRIC_DEFAULT_CONFIG,
Expand All @@ -187,7 +192,8 @@ def hook_mock_pull(mocker, mock_pull):
</details>

ℹ️ *Bundle size includes cached data from a previous commit
"""),

"""),
id="comment_increase_size_cached_values",
),
pytest.param(
Expand All @@ -199,6 +205,7 @@ def hook_mock_pull(mocker, mock_pull):
percentage_delta=-2.56,
),
],
{},
-0.52,
{
**PATCH_CENTRIC_DEFAULT_CONFIG,
Expand All @@ -218,7 +225,8 @@ def hook_mock_pull(mocker, mock_pull):
| ----------- | ---- | ------ |
| test-bundle | 123.46kB | 3.46kB (-2.56%) :arrow_down: |

</details>"""),
</details>
"""),
id="comment_decrease_size",
),
pytest.param(
Expand All @@ -230,6 +238,7 @@ def hook_mock_pull(mocker, mock_pull):
percentage_delta=0.0,
),
],
{},
0,
{
**PATCH_CENTRIC_DEFAULT_CONFIG,
Expand All @@ -243,13 +252,142 @@ def hook_mock_pull(mocker, mock_pull):

Bundle size has no change :white_check_mark:


"""),
id="comment_no_change",
),
pytest.param(
[
BundleChange(
bundle_name="added-bundle",
change_type=BundleChange.ChangeType.ADDED,
size_delta=12345,
percentage_delta=5.56,
),
BundleChange(
bundle_name="changed-bundle",
change_type=BundleChange.ChangeType.CHANGED,
size_delta=3456,
percentage_delta=0.35,
),
BundleChange(
bundle_name="removed-bundle",
change_type=BundleChange.ChangeType.REMOVED,
size_delta=-1234,
percentage_delta=-1.23,
),
],
{
"BundleA": [
RouteChange(
route_name="/users",
change_type=RouteChange.ChangeType.ADDED,
size_delta=1000,
size_base=0,
size_head=1000,
percentage_delta=100,
),
RouteChange(
route_name="/faq",
change_type=RouteChange.ChangeType.REMOVED,
size_delta=-5000,
size_base=5000,
size_head=0,
percentage_delta=-100.0,
),
RouteChange(
route_name="/careers",
change_type=RouteChange.ChangeType.CHANGED,
size_delta=10000,
size_base=20000,
size_head=30000,
percentage_delta=50.0,
),
RouteChange(
route_name="/no-change",
change_type=RouteChange.ChangeType.CHANGED,
size_delta=0,
size_base=999999,
size_head=999999,
percentage_delta=0,
),
],
"BundleB": [
RouteChange(
route_name="/users",
change_type=RouteChange.ChangeType.ADDED,
size_delta=1000,
size_base=0,
size_head=1000,
percentage_delta=100,
),
RouteChange(
route_name="/faq",
change_type=RouteChange.ChangeType.REMOVED,
size_delta=-5000,
size_base=5000,
size_head=0,
percentage_delta=-100.0,
),
RouteChange(
route_name="/about-us",
change_type=RouteChange.ChangeType.CHANGED,
size_delta=10000,
size_base=20000,
size_head=30000,
percentage_delta=50.0,
),
],
},
5.56,
{
**PATCH_CENTRIC_DEFAULT_CONFIG,
"bundle_analysis": {
"status": "informational",
"warning_threshold": ["percentage", 5.0],
},
},
dedent("""\
## [Bundle](URL) Report

Changes will increase total bundle size by 14.57kB (5.56%) :arrow_up::warning:, exceeding the [configured](https://docs.codecov.com/docs/javascript-bundle-analysis#main-features) threshold of 5%.

| Bundle name | Size | Change |
| ----------- | ---- | ------ |
| added-bundle | 123.46kB | 12.35kB (5.56%) :arrow_up::warning: |
| changed-bundle | 123.46kB | 3.46kB (0.35%) :arrow_up: |
| removed-bundle | (removed) | 1.23kB (-1.23%) :arrow_down: |

<details>
<summary>View changes by path for bundle: BundleA</summary>

| File path | Size | Change |
| --------- | ---- | ------ |
| **/users** _(New)_ | 1.0kB | 1.0kB (100%) :rocket: |
| ~~**/faq**~~ _(Deleted)_ | 0 bytes | 5.0kB (-100.0%) :wastebasket: |
| /careers | 30.0kB | 10.0kB (50.0%) |

</details>

<details>
<summary>View changes by path for bundle: BundleB</summary>

| File path | Size | Change |
| --------- | ---- | ------ |
| **/users** _(New)_ | 1.0kB | 1.0kB (100%) :rocket: |
| ~~**/faq**~~ _(Deleted)_ | 0 bytes | 5.0kB (-100.0%) :wastebasket: |
| /about-us | 30.0kB | 10.0kB (50.0%) |

</details>

"""),
id="comparison_by_file_path",
),
],
)
def test_bundle_analysis_notify(
bundle_changes: list[BundleChange],
bundle_routes_changes: dict[str, list[RouteChange]],
percent_change: float,
user_config: dict,
expected_message: str,
Expand Down Expand Up @@ -302,6 +440,10 @@ def test_bundle_analysis_notify(
"shared.bundle_analysis.comparison.BundleAnalysisComparison.bundle_changes",
return_value=bundle_changes,
)
mocker.patch(
"shared.bundle_analysis.comparison.BundleAnalysisComparison.bundle_routes_changes",
return_value=bundle_routes_changes,
)
mock_percentage = mocker.patch(
"shared.bundle_analysis.comparison.BundleAnalysisComparison.percentage_delta",
new_callable=PropertyMock,
Expand Down
Loading
0