Skip to content
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

Failed check and status messaging in comment, part IV #1042

Merged
merged 2 commits into from
Jan 31, 2025
Merged

Conversation

nora-codecov
Copy link
Contributor

when user has:
project checks notifier OR project status notifier
AND
comment notifier
AND
has defined removed_code_behavior as adjust_base in their codecov.yml
AND
the project check/status fails
AND
the adjusted_base coverage does NOT allow the check/status to pass
THEN
add some helper text to the comment notifier to point out that the check/status failed, with links to rcb and adjust_base docs, and tell them the coverage on the head vs the adjusted base.

codecov/engineering-team#1607

@nora-codecov nora-codecov requested a review from a team January 28, 2025 22:17
@codecov-notifications
Copy link

codecov-notifications bot commented Jan 28, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

Copy link

github-actions bot commented Jan 28, 2025

✅ All tests successful. No failed tests were found.

📣 Thoughts on this report? Let Codecov know! | Powered by Codecov

Copy link
Contributor

@giovanni-guidini giovanni-guidini left a comment

Choose a reason for hiding this comment

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

The code LGTM. Left a nit comment about enum.

I do have 1 question about this:
the helper text is a dictionary, and the helper-text-section will write all helper texts in this dictionary.

If adjust_base failed then the regular project check also failed - by definition. Wouldn't that also create a helper text?

My question is: if there are 2 helper texts in the help text dict, will the comment have 2 messages about virtually the same thing?
I haven't seen a test for this case.

@@ -27,16 +27,24 @@ class StatusResult(TypedDict):

CUSTOM_TARGET_TEXT_PATCH_KEY = "custom_target_helper_text_patch"
Copy link
Contributor

Choose a reason for hiding this comment

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

With so many keys, maybe it's more organized to create an Enum for them?

Copy link
Contributor

Choose a reason for hiding this comment

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

Or a TypedDict, where you have safety and autocompletion when writing keys, but you can iterate over only the values, or the k/v pairs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated!

@nora-codecov
Copy link
Contributor Author

My question is: if there are 2 helper texts in the help text dict, will the comment have 2 messages about virtually the same thing? I haven't seen a test for this case.

yes and no!

yes, you can have more than 1 helper text, but I think they are not about the same thing (therefore it is useful to have both). tested and attached a screenshot to this ticket. I designed the helper text system with this case in mind - each helper text should be about an independent issue, so that the comment can have one or many.

However, if the user has defined a custom target (this is what triggers the other 2 helper text messages), we don't do the adjust base behavior, so they would never have helper text about project target and adjust base. So in this case, will the comment have 2 messages about virtually the same thing -> no

@codecov-qa
Copy link

codecov-qa bot commented Jan 30, 2025

❌ 3 Tests Failed:

Tests completed Failed Passed Skipped
1794 3 1791 9
View the top 3 failed tests by shortest run time
services/notification/notifiers/tests/unit/test_status.py::TestProjectStatusNotifier::test_adjust_base_behavior[not_enough_hits_removed_for_status_to_pass]
Stack Traces | 0.025s run time
self = <test_status.TestProjectStatusNotifier object at 0x7f5fb36754e0>
mocker = <pytest_mock.plugin.MockFixture object at 0x7f5fa81c5d90>
base_totals = ReportTotals(files=0, lines=0, hits=1980, misses=120, partials=0, coverage=0, branches=0, methods=0, messages=0, sessions=0, complexity=0, complexity_total=0, diff=0)
head_totals = ReportTotals(files=0, lines=0, hits=1974, misses=120, partials=0, coverage=94.26934, branches=0, methods=0, messages=0, sessions=0, complexity=0, complexity_total=0, diff=0)
impacted_files = [{'removed_diff_coverage': [(1, 'h'), (2, 'h'), (3, 'h')]}]
expected = (None, {'rcb_adjust_base_helper_text': 'Your project status has failed because the head coverage (94.27%) is below the...crease the head coverage or adjust the [Removed Code Behavior](https://docs.codecov.com/docs/removed-code-behavior).'})

    @pytest.mark.parametrize(
        "base_totals, head_totals, impacted_files, expected",
        [
            pytest.param(
                ReportTotals(hits=1980, misses=120, partials=0),
                ReportTotals(
                    hits=1974,
                    misses=120,
                    partials=0,
                    coverage=round((1974 / (1974 + 120)) * 100, 5),
                ),
                [
                    {
                        "removed_diff_coverage": [
                            (1, "h"),
                            (2, "h"),
                            (3, "h"),
                            (4, "h"),
                            (5, "h"),
                            (6, "h"),
                            (7, "h"),
                            (8, "h"),
                            (9, "h"),
                            (10, "h"),
                            (11, "h"),
                            (12, "h"),
                            (13, "h"),
                            (14, "h"),
                            (15, "h"),
                        ]
                    }
                ],
                (
                    (
                        "success",
                        ", passed because coverage increased by 0.02% when compared to adjusted base (94.24%)",
                    ),
                    {},
                ),
                id="many_removed_hits_makes_head_more_covered_than_base",
            ),
            pytest.param(
                ReportTotals(hits=1980, misses=120, partials=0),
                ReportTotals(
                    hits=1974,
                    misses=120,
                    partials=0,
                    coverage=round((1974 / (1974 + 120)) * 100, 5),
                ),
                [
                    {
                        "removed_diff_coverage": [
                            (1, "h"),
                            (2, "h"),
                            (3, "h"),
                            (4, "h"),
                            (5, "h"),
                            (6, "h"),
                        ]
                    }
                ],
                (
                    (
                        "success",
                        ", passed because coverage increased by 0% when compared to adjusted base (94.27%)",
                    ),
                    {},
                ),
                id="many_removed_hits_makes_head_same_as_base",
            ),
            pytest.param(
                ReportTotals(hits=1980, misses=120, partials=0),
                ReportTotals(
                    hits=1974,
                    misses=120,
                    partials=0,
                    coverage=round((1974 / (1974 + 120)) * 100, 5),
                ),
                [
                    {
                        "removed_diff_coverage": [
                            (1, "h"),
                            (2, "h"),
                            (3, "h"),
                        ]
                    }
                ],
                (
                    None,
                    {
                        HelperTextKey.RCB_ADJUST_BASE.value: HELPER_TEXT_MAP[
                            HelperTextKey.RCB_ADJUST_BASE
                        ].value.format(
                            notification_type="status",
                            coverage=94.27,
                            adjusted_base_cov=94.28,
                        ),
                    },
                ),
                id="not_enough_hits_removed_for_status_to_pass",
            ),
            pytest.param(
                ReportTotals(hits=0, misses=0, partials=0),
                ReportTotals(hits=0, misses=0, partials=0, coverage="100"),
                [],
                (None, {}),
                id="zero_coverage",
            ),
        ],
    )
    def test_adjust_base_behavior(
        self, mocker, base_totals, head_totals, impacted_files, expected
    ):
        comparison = mocker.MagicMock(
            name="fake-comparison",
            get_impacted_files=MagicMock(return_value={"files": impacted_files}),
            project_coverage_base=FullCommit(
                commit=None, report=Report(totals=base_totals)
            ),
            head=FullCommit(commit=CommitFactory(), report=Report(totals=head_totals)),
        )
        settings = {"target": "auto"}
        status_mixin = ProjectStatusNotifier(
            repository="repo",
            title="fake-notifier",
            notifier_yaml_settings=settings,
            notifier_site_settings={},
            current_yaml=settings,
            repository_service={},
        )
>       result = status_mixin._apply_adjust_base_behavior(
            comparison, notification_type="status"
        )

.../tests/unit/test_status.py:1651: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <services.notification.notifiers.status.project.ProjectStatusNotifier object at 0x7f5fa09f93d0>
comparison = <MagicMock name='fake-comparison' id='140048713404768'>
notification_type = 'status'

    def _apply_adjust_base_behavior(
        self,
        comparison: ComparisonProxy | FilteredComparison,
        notification_type: str,
    ) -> tuple[tuple[str, str] | None, dict]:
        """
        Rule for passing project status on adjust_base behavior:
        We adjust the BASE of the comparison by removing from it lines that were removed in HEAD
        And then re-calculate BASE coverage and compare it to HEAD coverage.
        """
        helper_text = {}
        log.info(
            "Applying adjust_base behavior to project status",
            extra=dict(commit=comparison.head.commit.commitid),
        )
        # If the user defined a target value for project coverage
        # Adjusting the base won't make HEAD change in relation to the target value
        # So we skip the calculation entirely
        if self.notifier_yaml_settings.get("target") not in ("auto", None):
            log.info(
                "Notifier settings specify target value. Skipping adjust_base.",
                extra=dict(commit=comparison.head.commit.commitid),
            )
            return None, helper_text
    
        impacted_files = comparison.get_impacted_files().get("files", [])
    
        hits_removed = 0
        misses_removed = 0
        partials_removed = 0
    
        for file_dict in impacted_files:
            removed_diff_coverage_list = file_dict.get("removed_diff_coverage")
            if removed_diff_coverage_list:
                hits_removed += sum(
                    1 if item[1] == "h" else 0 for item in removed_diff_coverage_list
                )
                misses_removed += sum(
                    1 if item[1] == "m" else 0 for item in removed_diff_coverage_list
                )
                partials_removed += sum(
                    1 if item[1] == "p" else 0 for item in removed_diff_coverage_list
                )
    
        base_totals = comparison.project_coverage_base.report.totals
        base_adjusted_hits = base_totals.hits - hits_removed
        base_adjusted_misses = base_totals.misses - misses_removed
        base_adjusted_partials = base_totals.partials - partials_removed
        base_adjusted_totals = (
            base_adjusted_hits + base_adjusted_misses + base_adjusted_partials
        )
    
        if not base_adjusted_totals:
            return None, helper_text
    
        # The coverage info is in percentage, so multiply by 100
        base_adjusted_coverage = (
            Decimal(base_adjusted_hits / base_adjusted_totals) * 100
        )
    
        head_coverage = Decimal(comparison.head.report.totals.coverage)
        log.info(
            "Adjust base applied to project status",
            extra=dict(
                commit=comparison.head.commit.commitid,
                base_adjusted_coverage=base_adjusted_coverage,
                head_coverage=head_coverage,
                hits_removed=hits_removed,
                misses_removed=misses_removed,
                partials_removed=partials_removed,
            ),
        )
        # the head coverage is rounded to five digits after the dot, using shared.helpers.numeric.ratio
        # so we should round the base adjusted coverage to the same amount of digits after the dot
        # Decimal.quantize: https://docs.python..../3/library/decimal.html#decimal.Decimal.quantize
        quantized_base_adjusted_coverage = base_adjusted_coverage.quantize(
            Decimal("0.00000")
        )
        rounded_base_adjusted_coverage = round_number(
            self.current_yaml, base_adjusted_coverage
        )
    
        if quantized_base_adjusted_coverage - head_coverage < Decimal("0.005"):
            rounded_difference = max(
                0,
                round_number(self.current_yaml, head_coverage - base_adjusted_coverage),
            )
            return (
                (
                    StatusState.success.value,
                    f", passed because coverage increased by {rounded_difference}% when compared to adjusted base ({rounded_base_adjusted_coverage}%)",
                ),
                helper_text,
            )
        # use rounded numbers for messages
        coverage_rounded = round_number(self.current_yaml, head_coverage)
    
        # their comparison failed despite the adjusted base, give them helper text about it
>       helper_text[HelperTextKey.RCB_ADJUST_BASE].value = HELPER_TEXT_MAP[
            HelperTextKey.RCB_ADJUST_BASE
        ].value.format(
            notification_type=notification_type,
            coverage=coverage_rounded,
            adjusted_base_cov=rounded_base_adjusted_coverage,
        )
E       KeyError: <HelperTextKey.RCB_ADJUST_BASE: 'rcb_adjust_base_helper_text'>

.../notifiers/mixins/status.py:345: KeyError
services/notification/notifiers/tests/unit/test_status.py::TestProjectStatusNotifier::test_notify_adjust_base_behavior_fail
Stack Traces | 0.066s run time
self = <test_status.TestProjectStatusNotifier object at 0x7f5fb44685a0>
mock_configuration = <shared.config.ConfigHelper object at 0x7f5fa1b376b0>
sample_comparison_negative_change = <services.comparison.ComparisonProxy object at 0x7f5fa1dd2090>
mocker = <pytest_mock.plugin.MockFixture object at 0x7f5fa81c6a50>

    def test_notify_adjust_base_behavior_fail(
        self, mock_configuration, sample_comparison_negative_change, mocker
    ):
        sample_comparison = sample_comparison_negative_change
        mock_get_impacted_files = mocker.patch.object(
            ComparisonProxy,
            "get_impacted_files",
            return_value={
                "files": [
                    {
                        "base_name": "tests/file1.py",
                        "head_name": "tests/file1.py",
                        # Not complete, but we only care about these fields
                        "removed_diff_coverage": [[1, "h"], [3, "m"], [4, "m"]],
                        "added_diff_coverage": [],
                        "unexpected_line_changes": [],
                    },
                    {
                        "base_name": "tests/file2.go",
                        "head_name": "tests/file2.go",
                        "removed_diff_coverage": [],
                        "added_diff_coverage": [],
                        "unexpected_line_changes": [],
                    },
                ],
            },
        )
        mock_configuration.params["setup"]["codecov_dashboard_url"] = "test.example.br"
        notifier = ProjectStatusNotifier(
            repository=sample_comparison.head.commit.repository,
            title="title",
            notifier_yaml_settings={"removed_code_behavior": "adjust_base"},
            notifier_site_settings=True,
            current_yaml=UserYaml({}),
            repository_service={},
        )
        # included helper text for this user because they have adjust_base in their yaml
        expected_result = {
            "message": f"50.00% (-10.00%) compared to {sample_comparison.project_coverage_base.commit.commitid[:7]}",
            "state": "failure",
            "included_helper_text": {
                HelperTextKey.RCB_ADJUST_BASE.value: HELPER_TEXT_MAP[
                    HelperTextKey.RCB_ADJUST_BASE
                ].value.format(
                    notification_type="status",
                    coverage="50.00",
                    adjusted_base_cov=71.43,
                )
            },
        }
>       result = notifier.build_payload(sample_comparison)

.../tests/unit/test_status.py:1807: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../notifiers/status/project.py:44: in build_payload
    result = self.get_project_status(
.../notifiers/mixins/status.py:437: in get_project_status
    removed_code_result, helper_text = self._apply_adjust_base_behavior(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <services.notification.notifiers.status.project.ProjectStatusNotifier object at 0x7f5fa09f6550>
comparison = <services.comparison.ComparisonProxy object at 0x7f5fa1dd2090>
notification_type = 'status'

    def _apply_adjust_base_behavior(
        self,
        comparison: ComparisonProxy | FilteredComparison,
        notification_type: str,
    ) -> tuple[tuple[str, str] | None, dict]:
        """
        Rule for passing project status on adjust_base behavior:
        We adjust the BASE of the comparison by removing from it lines that were removed in HEAD
        And then re-calculate BASE coverage and compare it to HEAD coverage.
        """
        helper_text = {}
        log.info(
            "Applying adjust_base behavior to project status",
            extra=dict(commit=comparison.head.commit.commitid),
        )
        # If the user defined a target value for project coverage
        # Adjusting the base won't make HEAD change in relation to the target value
        # So we skip the calculation entirely
        if self.notifier_yaml_settings.get("target") not in ("auto", None):
            log.info(
                "Notifier settings specify target value. Skipping adjust_base.",
                extra=dict(commit=comparison.head.commit.commitid),
            )
            return None, helper_text
    
        impacted_files = comparison.get_impacted_files().get("files", [])
    
        hits_removed = 0
        misses_removed = 0
        partials_removed = 0
    
        for file_dict in impacted_files:
            removed_diff_coverage_list = file_dict.get("removed_diff_coverage")
            if removed_diff_coverage_list:
                hits_removed += sum(
                    1 if item[1] == "h" else 0 for item in removed_diff_coverage_list
                )
                misses_removed += sum(
                    1 if item[1] == "m" else 0 for item in removed_diff_coverage_list
                )
                partials_removed += sum(
                    1 if item[1] == "p" else 0 for item in removed_diff_coverage_list
                )
    
        base_totals = comparison.project_coverage_base.report.totals
        base_adjusted_hits = base_totals.hits - hits_removed
        base_adjusted_misses = base_totals.misses - misses_removed
        base_adjusted_partials = base_totals.partials - partials_removed
        base_adjusted_totals = (
            base_adjusted_hits + base_adjusted_misses + base_adjusted_partials
        )
    
        if not base_adjusted_totals:
            return None, helper_text
    
        # The coverage info is in percentage, so multiply by 100
        base_adjusted_coverage = (
            Decimal(base_adjusted_hits / base_adjusted_totals) * 100
        )
    
        head_coverage = Decimal(comparison.head.report.totals.coverage)
        log.info(
            "Adjust base applied to project status",
            extra=dict(
                commit=comparison.head.commit.commitid,
                base_adjusted_coverage=base_adjusted_coverage,
                head_coverage=head_coverage,
                hits_removed=hits_removed,
                misses_removed=misses_removed,
                partials_removed=partials_removed,
            ),
        )
        # the head coverage is rounded to five digits after the dot, using shared.helpers.numeric.ratio
        # so we should round the base adjusted coverage to the same amount of digits after the dot
        # Decimal.quantize: https://docs.python..../3/library/decimal.html#decimal.Decimal.quantize
        quantized_base_adjusted_coverage = base_adjusted_coverage.quantize(
            Decimal("0.00000")
        )
        rounded_base_adjusted_coverage = round_number(
            self.current_yaml, base_adjusted_coverage
        )
    
        if quantized_base_adjusted_coverage - head_coverage < Decimal("0.005"):
            rounded_difference = max(
                0,
                round_number(self.current_yaml, head_coverage - base_adjusted_coverage),
            )
            return (
                (
                    StatusState.success.value,
                    f", passed because coverage increased by {rounded_difference}% when compared to adjusted base ({rounded_base_adjusted_coverage}%)",
                ),
                helper_text,
            )
        # use rounded numbers for messages
        coverage_rounded = round_number(self.current_yaml, head_coverage)
    
        # their comparison failed despite the adjusted base, give them helper text about it
>       helper_text[HelperTextKey.RCB_ADJUST_BASE].value = HELPER_TEXT_MAP[
            HelperTextKey.RCB_ADJUST_BASE
        ].value.format(
            notification_type=notification_type,
            coverage=coverage_rounded,
            adjusted_base_cov=rounded_base_adjusted_coverage,
        )
E       KeyError: <HelperTextKey.RCB_ADJUST_BASE: 'rcb_adjust_base_helper_text'>

.../notifiers/mixins/status.py:345: KeyError
services/notification/notifiers/tests/unit/test_status.py::TestProjectStatusNotifier::test_notify_rcb_default
Stack Traces | 0.067s run time
self = <test_status.TestProjectStatusNotifier object at 0x7f5fb4468a00>
mock_configuration = <shared.config.ConfigHelper object at 0x7f5fa1dffad0>
sample_comparison_negative_change = <services.comparison.ComparisonProxy object at 0x7f5fa0d77710>
mocker = <pytest_mock.plugin.MockFixture object at 0x7f5fa0d77050>

    def test_notify_rcb_default(
        self, mock_configuration, sample_comparison_negative_change, mocker
    ):
        sample_comparison = sample_comparison_negative_change
        mock_get_impacted_files = mocker.patch.object(
            ComparisonProxy,
            "get_impacted_files",
            return_value={
                "files": [
                    {
                        "base_name": "tests/file1.py",
                        "head_name": "tests/file1.py",
                        # Not complete, but we only care about these fields
                        "removed_diff_coverage": [[1, "h"], [3, "m"], [4, "m"]],
                        "added_diff_coverage": [],
                        "unexpected_line_changes": [],
                    },
                    {
                        "base_name": "tests/file2.go",
                        "head_name": "tests/file2.go",
                        "removed_diff_coverage": [],
                        "added_diff_coverage": [],
                        "unexpected_line_changes": [],
                    },
                ],
            },
        )
        mock_configuration.params["setup"]["codecov_dashboard_url"] = "test.example.br"
        notifier = ProjectStatusNotifier(
            repository=sample_comparison.head.commit.repository,
            title="title",
            notifier_yaml_settings={},
            notifier_site_settings=True,
            current_yaml=UserYaml({}),
            repository_service={},
        )
        # NO helper text for this user because they have NOT specified adjust_base in their yaml
        expected_result = {
            "message": f"50.00% (-10.00%) compared to {sample_comparison.project_coverage_base.commit.commitid[:7]}",
            "state": "failure",
            "included_helper_text": {},
        }
>       result = notifier.build_payload(sample_comparison)

.../tests/unit/test_status.py:1853: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../notifiers/status/project.py:44: in build_payload
    result = self.get_project_status(
.../notifiers/mixins/status.py:437: in get_project_status
    removed_code_result, helper_text = self._apply_adjust_base_behavior(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <services.notification.notifiers.status.project.ProjectStatusNotifier object at 0x7f5fa0828950>
comparison = <services.comparison.ComparisonProxy object at 0x7f5fa0d77710>
notification_type = 'status'

    def _apply_adjust_base_behavior(
        self,
        comparison: ComparisonProxy | FilteredComparison,
        notification_type: str,
    ) -> tuple[tuple[str, str] | None, dict]:
        """
        Rule for passing project status on adjust_base behavior:
        We adjust the BASE of the comparison by removing from it lines that were removed in HEAD
        And then re-calculate BASE coverage and compare it to HEAD coverage.
        """
        helper_text = {}
        log.info(
            "Applying adjust_base behavior to project status",
            extra=dict(commit=comparison.head.commit.commitid),
        )
        # If the user defined a target value for project coverage
        # Adjusting the base won't make HEAD change in relation to the target value
        # So we skip the calculation entirely
        if self.notifier_yaml_settings.get("target") not in ("auto", None):
            log.info(
                "Notifier settings specify target value. Skipping adjust_base.",
                extra=dict(commit=comparison.head.commit.commitid),
            )
            return None, helper_text
    
        impacted_files = comparison.get_impacted_files().get("files", [])
    
        hits_removed = 0
        misses_removed = 0
        partials_removed = 0
    
        for file_dict in impacted_files:
            removed_diff_coverage_list = file_dict.get("removed_diff_coverage")
            if removed_diff_coverage_list:
                hits_removed += sum(
                    1 if item[1] == "h" else 0 for item in removed_diff_coverage_list
                )
                misses_removed += sum(
                    1 if item[1] == "m" else 0 for item in removed_diff_coverage_list
                )
                partials_removed += sum(
                    1 if item[1] == "p" else 0 for item in removed_diff_coverage_list
                )
    
        base_totals = comparison.project_coverage_base.report.totals
        base_adjusted_hits = base_totals.hits - hits_removed
        base_adjusted_misses = base_totals.misses - misses_removed
        base_adjusted_partials = base_totals.partials - partials_removed
        base_adjusted_totals = (
            base_adjusted_hits + base_adjusted_misses + base_adjusted_partials
        )
    
        if not base_adjusted_totals:
            return None, helper_text
    
        # The coverage info is in percentage, so multiply by 100
        base_adjusted_coverage = (
            Decimal(base_adjusted_hits / base_adjusted_totals) * 100
        )
    
        head_coverage = Decimal(comparison.head.report.totals.coverage)
        log.info(
            "Adjust base applied to project status",
            extra=dict(
                commit=comparison.head.commit.commitid,
                base_adjusted_coverage=base_adjusted_coverage,
                head_coverage=head_coverage,
                hits_removed=hits_removed,
                misses_removed=misses_removed,
                partials_removed=partials_removed,
            ),
        )
        # the head coverage is rounded to five digits after the dot, using shared.helpers.numeric.ratio
        # so we should round the base adjusted coverage to the same amount of digits after the dot
        # Decimal.quantize: https://docs.python..../3/library/decimal.html#decimal.Decimal.quantize
        quantized_base_adjusted_coverage = base_adjusted_coverage.quantize(
            Decimal("0.00000")
        )
        rounded_base_adjusted_coverage = round_number(
            self.current_yaml, base_adjusted_coverage
        )
    
        if quantized_base_adjusted_coverage - head_coverage < Decimal("0.005"):
            rounded_difference = max(
                0,
                round_number(self.current_yaml, head_coverage - base_adjusted_coverage),
            )
            return (
                (
                    StatusState.success.value,
                    f", passed because coverage increased by {rounded_difference}% when compared to adjusted base ({rounded_base_adjusted_coverage}%)",
                ),
                helper_text,
            )
        # use rounded numbers for messages
        coverage_rounded = round_number(self.current_yaml, head_coverage)
    
        # their comparison failed despite the adjusted base, give them helper text about it
>       helper_text[HelperTextKey.RCB_ADJUST_BASE].value = HELPER_TEXT_MAP[
            HelperTextKey.RCB_ADJUST_BASE
        ].value.format(
            notification_type=notification_type,
            coverage=coverage_rounded,
            adjusted_base_cov=rounded_base_adjusted_coverage,
        )
E       KeyError: <HelperTextKey.RCB_ADJUST_BASE: 'rcb_adjust_base_helper_text'>

.../notifiers/mixins/status.py:345: KeyError

To view more test analytics, go to the Test Analytics Dashboard
📢 Thoughts on this report? Let us know!

Copy link

❌ 3 Tests Failed:

Tests completed Failed Passed Skipped
1794 3 1791 9
View the top 3 failed tests by shortest run time
services/notification/notifiers/tests/unit/test_status.py::TestProjectStatusNotifier::test_adjust_base_behavior[not_enough_hits_removed_for_status_to_pass]
Stack Traces | 0.025s run time
self = <test_status.TestProjectStatusNotifier object at 0x7f5fb36754e0>
mocker = <pytest_mock.plugin.MockFixture object at 0x7f5fa81c5d90>
base_totals = ReportTotals(files=0, lines=0, hits=1980, misses=120, partials=0, coverage=0, branches=0, methods=0, messages=0, sessions=0, complexity=0, complexity_total=0, diff=0)
head_totals = ReportTotals(files=0, lines=0, hits=1974, misses=120, partials=0, coverage=94.26934, branches=0, methods=0, messages=0, sessions=0, complexity=0, complexity_total=0, diff=0)
impacted_files = [{'removed_diff_coverage': [(1, 'h'), (2, 'h'), (3, 'h')]}]
expected = (None, {'rcb_adjust_base_helper_text': 'Your project status has failed because the head coverage (94.27%) is below the...crease the head coverage or adjust the [Removed Code Behavior](https://docs.codecov.com/docs/removed-code-behavior).'})

    @pytest.mark.parametrize(
        "base_totals, head_totals, impacted_files, expected",
        [
            pytest.param(
                ReportTotals(hits=1980, misses=120, partials=0),
                ReportTotals(
                    hits=1974,
                    misses=120,
                    partials=0,
                    coverage=round((1974 / (1974 + 120)) * 100, 5),
                ),
                [
                    {
                        "removed_diff_coverage": [
                            (1, "h"),
                            (2, "h"),
                            (3, "h"),
                            (4, "h"),
                            (5, "h"),
                            (6, "h"),
                            (7, "h"),
                            (8, "h"),
                            (9, "h"),
                            (10, "h"),
                            (11, "h"),
                            (12, "h"),
                            (13, "h"),
                            (14, "h"),
                            (15, "h"),
                        ]
                    }
                ],
                (
                    (
                        "success",
                        ", passed because coverage increased by 0.02% when compared to adjusted base (94.24%)",
                    ),
                    {},
                ),
                id="many_removed_hits_makes_head_more_covered_than_base",
            ),
            pytest.param(
                ReportTotals(hits=1980, misses=120, partials=0),
                ReportTotals(
                    hits=1974,
                    misses=120,
                    partials=0,
                    coverage=round((1974 / (1974 + 120)) * 100, 5),
                ),
                [
                    {
                        "removed_diff_coverage": [
                            (1, "h"),
                            (2, "h"),
                            (3, "h"),
                            (4, "h"),
                            (5, "h"),
                            (6, "h"),
                        ]
                    }
                ],
                (
                    (
                        "success",
                        ", passed because coverage increased by 0% when compared to adjusted base (94.27%)",
                    ),
                    {},
                ),
                id="many_removed_hits_makes_head_same_as_base",
            ),
            pytest.param(
                ReportTotals(hits=1980, misses=120, partials=0),
                ReportTotals(
                    hits=1974,
                    misses=120,
                    partials=0,
                    coverage=round((1974 / (1974 + 120)) * 100, 5),
                ),
                [
                    {
                        "removed_diff_coverage": [
                            (1, "h"),
                            (2, "h"),
                            (3, "h"),
                        ]
                    }
                ],
                (
                    None,
                    {
                        HelperTextKey.RCB_ADJUST_BASE.value: HELPER_TEXT_MAP[
                            HelperTextKey.RCB_ADJUST_BASE
                        ].value.format(
                            notification_type="status",
                            coverage=94.27,
                            adjusted_base_cov=94.28,
                        ),
                    },
                ),
                id="not_enough_hits_removed_for_status_to_pass",
            ),
            pytest.param(
                ReportTotals(hits=0, misses=0, partials=0),
                ReportTotals(hits=0, misses=0, partials=0, coverage="100"),
                [],
                (None, {}),
                id="zero_coverage",
            ),
        ],
    )
    def test_adjust_base_behavior(
        self, mocker, base_totals, head_totals, impacted_files, expected
    ):
        comparison = mocker.MagicMock(
            name="fake-comparison",
            get_impacted_files=MagicMock(return_value={"files": impacted_files}),
            project_coverage_base=FullCommit(
                commit=None, report=Report(totals=base_totals)
            ),
            head=FullCommit(commit=CommitFactory(), report=Report(totals=head_totals)),
        )
        settings = {"target": "auto"}
        status_mixin = ProjectStatusNotifier(
            repository="repo",
            title="fake-notifier",
            notifier_yaml_settings=settings,
            notifier_site_settings={},
            current_yaml=settings,
            repository_service={},
        )
>       result = status_mixin._apply_adjust_base_behavior(
            comparison, notification_type="status"
        )

.../tests/unit/test_status.py:1651: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <services.notification.notifiers.status.project.ProjectStatusNotifier object at 0x7f5fa09f93d0>
comparison = <MagicMock name='fake-comparison' id='140048713404768'>
notification_type = 'status'

    def _apply_adjust_base_behavior(
        self,
        comparison: ComparisonProxy | FilteredComparison,
        notification_type: str,
    ) -> tuple[tuple[str, str] | None, dict]:
        """
        Rule for passing project status on adjust_base behavior:
        We adjust the BASE of the comparison by removing from it lines that were removed in HEAD
        And then re-calculate BASE coverage and compare it to HEAD coverage.
        """
        helper_text = {}
        log.info(
            "Applying adjust_base behavior to project status",
            extra=dict(commit=comparison.head.commit.commitid),
        )
        # If the user defined a target value for project coverage
        # Adjusting the base won't make HEAD change in relation to the target value
        # So we skip the calculation entirely
        if self.notifier_yaml_settings.get("target") not in ("auto", None):
            log.info(
                "Notifier settings specify target value. Skipping adjust_base.",
                extra=dict(commit=comparison.head.commit.commitid),
            )
            return None, helper_text
    
        impacted_files = comparison.get_impacted_files().get("files", [])
    
        hits_removed = 0
        misses_removed = 0
        partials_removed = 0
    
        for file_dict in impacted_files:
            removed_diff_coverage_list = file_dict.get("removed_diff_coverage")
            if removed_diff_coverage_list:
                hits_removed += sum(
                    1 if item[1] == "h" else 0 for item in removed_diff_coverage_list
                )
                misses_removed += sum(
                    1 if item[1] == "m" else 0 for item in removed_diff_coverage_list
                )
                partials_removed += sum(
                    1 if item[1] == "p" else 0 for item in removed_diff_coverage_list
                )
    
        base_totals = comparison.project_coverage_base.report.totals
        base_adjusted_hits = base_totals.hits - hits_removed
        base_adjusted_misses = base_totals.misses - misses_removed
        base_adjusted_partials = base_totals.partials - partials_removed
        base_adjusted_totals = (
            base_adjusted_hits + base_adjusted_misses + base_adjusted_partials
        )
    
        if not base_adjusted_totals:
            return None, helper_text
    
        # The coverage info is in percentage, so multiply by 100
        base_adjusted_coverage = (
            Decimal(base_adjusted_hits / base_adjusted_totals) * 100
        )
    
        head_coverage = Decimal(comparison.head.report.totals.coverage)
        log.info(
            "Adjust base applied to project status",
            extra=dict(
                commit=comparison.head.commit.commitid,
                base_adjusted_coverage=base_adjusted_coverage,
                head_coverage=head_coverage,
                hits_removed=hits_removed,
                misses_removed=misses_removed,
                partials_removed=partials_removed,
            ),
        )
        # the head coverage is rounded to five digits after the dot, using shared.helpers.numeric.ratio
        # so we should round the base adjusted coverage to the same amount of digits after the dot
        # Decimal.quantize: https://docs.python..../3/library/decimal.html#decimal.Decimal.quantize
        quantized_base_adjusted_coverage = base_adjusted_coverage.quantize(
            Decimal("0.00000")
        )
        rounded_base_adjusted_coverage = round_number(
            self.current_yaml, base_adjusted_coverage
        )
    
        if quantized_base_adjusted_coverage - head_coverage < Decimal("0.005"):
            rounded_difference = max(
                0,
                round_number(self.current_yaml, head_coverage - base_adjusted_coverage),
            )
            return (
                (
                    StatusState.success.value,
                    f", passed because coverage increased by {rounded_difference}% when compared to adjusted base ({rounded_base_adjusted_coverage}%)",
                ),
                helper_text,
            )
        # use rounded numbers for messages
        coverage_rounded = round_number(self.current_yaml, head_coverage)
    
        # their comparison failed despite the adjusted base, give them helper text about it
>       helper_text[HelperTextKey.RCB_ADJUST_BASE].value = HELPER_TEXT_MAP[
            HelperTextKey.RCB_ADJUST_BASE
        ].value.format(
            notification_type=notification_type,
            coverage=coverage_rounded,
            adjusted_base_cov=rounded_base_adjusted_coverage,
        )
E       KeyError: <HelperTextKey.RCB_ADJUST_BASE: 'rcb_adjust_base_helper_text'>

.../notifiers/mixins/status.py:345: KeyError
services/notification/notifiers/tests/unit/test_status.py::TestProjectStatusNotifier::test_notify_adjust_base_behavior_fail
Stack Traces | 0.066s run time
self = <test_status.TestProjectStatusNotifier object at 0x7f5fb44685a0>
mock_configuration = <shared.config.ConfigHelper object at 0x7f5fa1b376b0>
sample_comparison_negative_change = <services.comparison.ComparisonProxy object at 0x7f5fa1dd2090>
mocker = <pytest_mock.plugin.MockFixture object at 0x7f5fa81c6a50>

    def test_notify_adjust_base_behavior_fail(
        self, mock_configuration, sample_comparison_negative_change, mocker
    ):
        sample_comparison = sample_comparison_negative_change
        mock_get_impacted_files = mocker.patch.object(
            ComparisonProxy,
            "get_impacted_files",
            return_value={
                "files": [
                    {
                        "base_name": "tests/file1.py",
                        "head_name": "tests/file1.py",
                        # Not complete, but we only care about these fields
                        "removed_diff_coverage": [[1, "h"], [3, "m"], [4, "m"]],
                        "added_diff_coverage": [],
                        "unexpected_line_changes": [],
                    },
                    {
                        "base_name": "tests/file2.go",
                        "head_name": "tests/file2.go",
                        "removed_diff_coverage": [],
                        "added_diff_coverage": [],
                        "unexpected_line_changes": [],
                    },
                ],
            },
        )
        mock_configuration.params["setup"]["codecov_dashboard_url"] = "test.example.br"
        notifier = ProjectStatusNotifier(
            repository=sample_comparison.head.commit.repository,
            title="title",
            notifier_yaml_settings={"removed_code_behavior": "adjust_base"},
            notifier_site_settings=True,
            current_yaml=UserYaml({}),
            repository_service={},
        )
        # included helper text for this user because they have adjust_base in their yaml
        expected_result = {
            "message": f"50.00% (-10.00%) compared to {sample_comparison.project_coverage_base.commit.commitid[:7]}",
            "state": "failure",
            "included_helper_text": {
                HelperTextKey.RCB_ADJUST_BASE.value: HELPER_TEXT_MAP[
                    HelperTextKey.RCB_ADJUST_BASE
                ].value.format(
                    notification_type="status",
                    coverage="50.00",
                    adjusted_base_cov=71.43,
                )
            },
        }
>       result = notifier.build_payload(sample_comparison)

.../tests/unit/test_status.py:1807: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../notifiers/status/project.py:44: in build_payload
    result = self.get_project_status(
.../notifiers/mixins/status.py:437: in get_project_status
    removed_code_result, helper_text = self._apply_adjust_base_behavior(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <services.notification.notifiers.status.project.ProjectStatusNotifier object at 0x7f5fa09f6550>
comparison = <services.comparison.ComparisonProxy object at 0x7f5fa1dd2090>
notification_type = 'status'

    def _apply_adjust_base_behavior(
        self,
        comparison: ComparisonProxy | FilteredComparison,
        notification_type: str,
    ) -> tuple[tuple[str, str] | None, dict]:
        """
        Rule for passing project status on adjust_base behavior:
        We adjust the BASE of the comparison by removing from it lines that were removed in HEAD
        And then re-calculate BASE coverage and compare it to HEAD coverage.
        """
        helper_text = {}
        log.info(
            "Applying adjust_base behavior to project status",
            extra=dict(commit=comparison.head.commit.commitid),
        )
        # If the user defined a target value for project coverage
        # Adjusting the base won't make HEAD change in relation to the target value
        # So we skip the calculation entirely
        if self.notifier_yaml_settings.get("target") not in ("auto", None):
            log.info(
                "Notifier settings specify target value. Skipping adjust_base.",
                extra=dict(commit=comparison.head.commit.commitid),
            )
            return None, helper_text
    
        impacted_files = comparison.get_impacted_files().get("files", [])
    
        hits_removed = 0
        misses_removed = 0
        partials_removed = 0
    
        for file_dict in impacted_files:
            removed_diff_coverage_list = file_dict.get("removed_diff_coverage")
            if removed_diff_coverage_list:
                hits_removed += sum(
                    1 if item[1] == "h" else 0 for item in removed_diff_coverage_list
                )
                misses_removed += sum(
                    1 if item[1] == "m" else 0 for item in removed_diff_coverage_list
                )
                partials_removed += sum(
                    1 if item[1] == "p" else 0 for item in removed_diff_coverage_list
                )
    
        base_totals = comparison.project_coverage_base.report.totals
        base_adjusted_hits = base_totals.hits - hits_removed
        base_adjusted_misses = base_totals.misses - misses_removed
        base_adjusted_partials = base_totals.partials - partials_removed
        base_adjusted_totals = (
            base_adjusted_hits + base_adjusted_misses + base_adjusted_partials
        )
    
        if not base_adjusted_totals:
            return None, helper_text
    
        # The coverage info is in percentage, so multiply by 100
        base_adjusted_coverage = (
            Decimal(base_adjusted_hits / base_adjusted_totals) * 100
        )
    
        head_coverage = Decimal(comparison.head.report.totals.coverage)
        log.info(
            "Adjust base applied to project status",
            extra=dict(
                commit=comparison.head.commit.commitid,
                base_adjusted_coverage=base_adjusted_coverage,
                head_coverage=head_coverage,
                hits_removed=hits_removed,
                misses_removed=misses_removed,
                partials_removed=partials_removed,
            ),
        )
        # the head coverage is rounded to five digits after the dot, using shared.helpers.numeric.ratio
        # so we should round the base adjusted coverage to the same amount of digits after the dot
        # Decimal.quantize: https://docs.python..../3/library/decimal.html#decimal.Decimal.quantize
        quantized_base_adjusted_coverage = base_adjusted_coverage.quantize(
            Decimal("0.00000")
        )
        rounded_base_adjusted_coverage = round_number(
            self.current_yaml, base_adjusted_coverage
        )
    
        if quantized_base_adjusted_coverage - head_coverage < Decimal("0.005"):
            rounded_difference = max(
                0,
                round_number(self.current_yaml, head_coverage - base_adjusted_coverage),
            )
            return (
                (
                    StatusState.success.value,
                    f", passed because coverage increased by {rounded_difference}% when compared to adjusted base ({rounded_base_adjusted_coverage}%)",
                ),
                helper_text,
            )
        # use rounded numbers for messages
        coverage_rounded = round_number(self.current_yaml, head_coverage)
    
        # their comparison failed despite the adjusted base, give them helper text about it
>       helper_text[HelperTextKey.RCB_ADJUST_BASE].value = HELPER_TEXT_MAP[
            HelperTextKey.RCB_ADJUST_BASE
        ].value.format(
            notification_type=notification_type,
            coverage=coverage_rounded,
            adjusted_base_cov=rounded_base_adjusted_coverage,
        )
E       KeyError: <HelperTextKey.RCB_ADJUST_BASE: 'rcb_adjust_base_helper_text'>

.../notifiers/mixins/status.py:345: KeyError
services/notification/notifiers/tests/unit/test_status.py::TestProjectStatusNotifier::test_notify_rcb_default
Stack Traces | 0.067s run time
self = <test_status.TestProjectStatusNotifier object at 0x7f5fb4468a00>
mock_configuration = <shared.config.ConfigHelper object at 0x7f5fa1dffad0>
sample_comparison_negative_change = <services.comparison.ComparisonProxy object at 0x7f5fa0d77710>
mocker = <pytest_mock.plugin.MockFixture object at 0x7f5fa0d77050>

    def test_notify_rcb_default(
        self, mock_configuration, sample_comparison_negative_change, mocker
    ):
        sample_comparison = sample_comparison_negative_change
        mock_get_impacted_files = mocker.patch.object(
            ComparisonProxy,
            "get_impacted_files",
            return_value={
                "files": [
                    {
                        "base_name": "tests/file1.py",
                        "head_name": "tests/file1.py",
                        # Not complete, but we only care about these fields
                        "removed_diff_coverage": [[1, "h"], [3, "m"], [4, "m"]],
                        "added_diff_coverage": [],
                        "unexpected_line_changes": [],
                    },
                    {
                        "base_name": "tests/file2.go",
                        "head_name": "tests/file2.go",
                        "removed_diff_coverage": [],
                        "added_diff_coverage": [],
                        "unexpected_line_changes": [],
                    },
                ],
            },
        )
        mock_configuration.params["setup"]["codecov_dashboard_url"] = "test.example.br"
        notifier = ProjectStatusNotifier(
            repository=sample_comparison.head.commit.repository,
            title="title",
            notifier_yaml_settings={},
            notifier_site_settings=True,
            current_yaml=UserYaml({}),
            repository_service={},
        )
        # NO helper text for this user because they have NOT specified adjust_base in their yaml
        expected_result = {
            "message": f"50.00% (-10.00%) compared to {sample_comparison.project_coverage_base.commit.commitid[:7]}",
            "state": "failure",
            "included_helper_text": {},
        }
>       result = notifier.build_payload(sample_comparison)

.../tests/unit/test_status.py:1853: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../notifiers/status/project.py:44: in build_payload
    result = self.get_project_status(
.../notifiers/mixins/status.py:437: in get_project_status
    removed_code_result, helper_text = self._apply_adjust_base_behavior(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <services.notification.notifiers.status.project.ProjectStatusNotifier object at 0x7f5fa0828950>
comparison = <services.comparison.ComparisonProxy object at 0x7f5fa0d77710>
notification_type = 'status'

    def _apply_adjust_base_behavior(
        self,
        comparison: ComparisonProxy | FilteredComparison,
        notification_type: str,
    ) -> tuple[tuple[str, str] | None, dict]:
        """
        Rule for passing project status on adjust_base behavior:
        We adjust the BASE of the comparison by removing from it lines that were removed in HEAD
        And then re-calculate BASE coverage and compare it to HEAD coverage.
        """
        helper_text = {}
        log.info(
            "Applying adjust_base behavior to project status",
            extra=dict(commit=comparison.head.commit.commitid),
        )
        # If the user defined a target value for project coverage
        # Adjusting the base won't make HEAD change in relation to the target value
        # So we skip the calculation entirely
        if self.notifier_yaml_settings.get("target") not in ("auto", None):
            log.info(
                "Notifier settings specify target value. Skipping adjust_base.",
                extra=dict(commit=comparison.head.commit.commitid),
            )
            return None, helper_text
    
        impacted_files = comparison.get_impacted_files().get("files", [])
    
        hits_removed = 0
        misses_removed = 0
        partials_removed = 0
    
        for file_dict in impacted_files:
            removed_diff_coverage_list = file_dict.get("removed_diff_coverage")
            if removed_diff_coverage_list:
                hits_removed += sum(
                    1 if item[1] == "h" else 0 for item in removed_diff_coverage_list
                )
                misses_removed += sum(
                    1 if item[1] == "m" else 0 for item in removed_diff_coverage_list
                )
                partials_removed += sum(
                    1 if item[1] == "p" else 0 for item in removed_diff_coverage_list
                )
    
        base_totals = comparison.project_coverage_base.report.totals
        base_adjusted_hits = base_totals.hits - hits_removed
        base_adjusted_misses = base_totals.misses - misses_removed
        base_adjusted_partials = base_totals.partials - partials_removed
        base_adjusted_totals = (
            base_adjusted_hits + base_adjusted_misses + base_adjusted_partials
        )
    
        if not base_adjusted_totals:
            return None, helper_text
    
        # The coverage info is in percentage, so multiply by 100
        base_adjusted_coverage = (
            Decimal(base_adjusted_hits / base_adjusted_totals) * 100
        )
    
        head_coverage = Decimal(comparison.head.report.totals.coverage)
        log.info(
            "Adjust base applied to project status",
            extra=dict(
                commit=comparison.head.commit.commitid,
                base_adjusted_coverage=base_adjusted_coverage,
                head_coverage=head_coverage,
                hits_removed=hits_removed,
                misses_removed=misses_removed,
                partials_removed=partials_removed,
            ),
        )
        # the head coverage is rounded to five digits after the dot, using shared.helpers.numeric.ratio
        # so we should round the base adjusted coverage to the same amount of digits after the dot
        # Decimal.quantize: https://docs.python..../3/library/decimal.html#decimal.Decimal.quantize
        quantized_base_adjusted_coverage = base_adjusted_coverage.quantize(
            Decimal("0.00000")
        )
        rounded_base_adjusted_coverage = round_number(
            self.current_yaml, base_adjusted_coverage
        )
    
        if quantized_base_adjusted_coverage - head_coverage < Decimal("0.005"):
            rounded_difference = max(
                0,
                round_number(self.current_yaml, head_coverage - base_adjusted_coverage),
            )
            return (
                (
                    StatusState.success.value,
                    f", passed because coverage increased by {rounded_difference}% when compared to adjusted base ({rounded_base_adjusted_coverage}%)",
                ),
                helper_text,
            )
        # use rounded numbers for messages
        coverage_rounded = round_number(self.current_yaml, head_coverage)
    
        # their comparison failed despite the adjusted base, give them helper text about it
>       helper_text[HelperTextKey.RCB_ADJUST_BASE].value = HELPER_TEXT_MAP[
            HelperTextKey.RCB_ADJUST_BASE
        ].value.format(
            notification_type=notification_type,
            coverage=coverage_rounded,
            adjusted_base_cov=rounded_base_adjusted_coverage,
        )
E       KeyError: <HelperTextKey.RCB_ADJUST_BASE: 'rcb_adjust_base_helper_text'>

.../notifiers/mixins/status.py:345: KeyError

To view more test analytics, go to the Test Analytics Dashboard
📢 Thoughts on this report? Let us know!

Copy link

codecov bot commented Jan 30, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 97.52%. Comparing base (6302730) to head (a379de0).
Report is 2 commits behind head on main.

✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1042   +/-   ##
=======================================
  Coverage   97.52%   97.52%           
=======================================
  Files         462      462           
  Lines       37902    37924   +22     
=======================================
+ Hits        36963    36985   +22     
  Misses        939      939           
Flag Coverage Δ
integration 42.88% <26.31%> (-0.02%) ⬇️
unit 90.17% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

⚠️ Impact Analysis from Codecov is deprecated and will be sunset on Jan 31 2025. See more

Copy link
Contributor

@giovanni-guidini giovanni-guidini left a comment

Choose a reason for hiding this comment

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

Thank you for clarifications

@nora-codecov nora-codecov added this pull request to the merge queue Jan 31, 2025
Merged via the queue into main with commit 9d423d7 Jan 31, 2025
38 of 40 checks passed
@nora-codecov nora-codecov deleted the nora/1607 branch January 31, 2025 18:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants