Skip to content
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
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,20 @@ jobs:
run: tox
env:
PYTEST_MAJOR_VERSION: 9
PYTEST_PLUGINS: pytest_github_actions_annotate_failures,xdist
PYTEST_PLUGINS: pytest_github_actions_annotate_failures,rerunfailures,xdist

- name: Run tests with PyTest 8
run: tox
env:
PYTEST_MAJOR_VERSION: 8
PYTEST_PLUGINS: pytest_github_actions_annotate_failures,xdist
PYTEST_PLUGINS: pytest_github_actions_annotate_failures,rerunfailures,xdist

- name: Run tests with PyTest 7
run: tox
if: runner.os != 'Windows'
env:
PYTEST_MAJOR_VERSION: 7
PYTEST_PLUGINS: pytest_github_actions_annotate_failures,xdist
PYTEST_PLUGINS: pytest_github_actions_annotate_failures,rerunfailures,xdist

post-test:
name: All tests passed
Expand Down
80 changes: 80 additions & 0 deletions plugin_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,86 @@ def test_fails(n):
assert {*lines.values()} == {1}


def test_annotation_rerunfailures_all_fail(testdir: pytest.Testdir):
"""Intermediate rerun failures should also be annotated."""
testdir.makepyfile(
"""
import pytest
pytest_plugins = ['pytest_github_actions_annotate_failures', 'rerunfailures']

def test_always_fails():
assert 0
"""
)
testdir.monkeypatch.setenv("GITHUB_ACTIONS", "true")
result = testdir.runpytest_subprocess("--reruns", "2")
lines = [
line
for line in result.errlines
if line.startswith("::error file=test_annotation_rerunfailures_all_fail.py")
]
# 1 initial run + 2 reruns = 3 annotations
assert len(lines) == 3


def test_annotation_rerunfailures_eventually_passes(testdir: pytest.Testdir):
"""Failures before a test eventually passes should still be annotated."""
testdir.makepyfile(
"""
import pytest
pytest_plugins = ['pytest_github_actions_annotate_failures', 'rerunfailures']

_attempt = 0

def test_flaky():
global _attempt
_attempt += 1
assert _attempt >= 2
"""
)
testdir.monkeypatch.setenv("GITHUB_ACTIONS", "true")
result = testdir.runpytest_subprocess("--reruns", "2")
lines = [
line
for line in result.errlines
if line.startswith(
"::error file=test_annotation_rerunfailures_eventually_passes.py"
)
]
# 1 initial failure, then passes on second attempt → 1 annotation
assert len(lines) == 1


def test_with_xdist_and_rerunfailures(
pytester: pytest.Pytester, monkeypatch: pytest.MonkeyPatch
):
"""Rerun annotations are emitted when xdist and rerunfailures are used together.

Under xdist, workers handle reruns and forward each rerun report to the
controller. The plugin is only registered on the controller, so the
controller's pytest_runtest_logreport sees both the intermediate 'rerun'
outcomes and the final 'failed' outcome — exactly once each.
"""
pytester.makepyfile(
"""
import pytest
pytest_plugins = ['pytest_github_actions_annotate_failures', 'xdist', 'rerunfailures']

def test_always_fails():
assert 0
"""
)
monkeypatch.setenv("GITHUB_ACTIONS", "true")
result = pytester.runpytest_subprocess("-n", "1", "--reruns", "2")
lines = [
line
for line in result.errlines
if line.startswith("::error file=test_with_xdist_and_rerunfailures.py")
]
# 1 initial run + 2 reruns = 3 annotations, no duplicates
assert len(lines) == 3


# Debugging / development tip:
# Add a breakpoint() to the place you are going to check,
# uncomment this example, and run it with:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pytest_github_actions_annotate_failures = "pytest_github_actions_annotate_failur

[dependency-groups]
dev = [{ include-group = "test" }]
test = ["packaging", "pytest-xdist"]
test = ["packaging", "pytest-rerunfailures", "pytest-xdist"]

[build-system]
requires = [
Expand Down
5 changes: 3 additions & 2 deletions pytest_github_actions_annotate_failures/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ def pytest_runtest_logreport(self, report: TestReport):
if os.environ.get("GITHUB_ACTIONS") != "true":
return

# Only handle failed tests in call phase
if report.when == "call" and report.failed:
# Only handle failed tests in call phase.
# Also handle 'rerun' outcome set by pytest-rerunfailures on intermediate failures.
if report.when == "call" and (report.failed or report.outcome == "rerun"):
filesystempath, lineno, _ = report.location

if lineno is not None:
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ PYTEST_MAJOR_VERSION =

[testenv]
requires =
>=4.42
tox>=4.42
dependency_groups = test
deps =
pytest7: pytest>=7.0.0,<8.0.0
Expand Down
Loading