Skip to content

Commit 9191068

Browse files
authored
Merge pull request #573 from py-cov-action/three-dot
2 parents 078b17d + d07a126 commit 9191068

File tree

9 files changed

+203
-155
lines changed

9 files changed

+203
-155
lines changed

coverage_comment/coverage.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -286,18 +286,7 @@ def get_diff_coverage_info(
286286
)
287287

288288

289-
def get_added_lines(
290-
git: subprocess.Git, base_ref: str
291-
) -> dict[pathlib.Path, list[int]]:
292-
# --unified=0 means we don't get any context lines for chunk, and we
293-
# don't merge chunks. This means the headers that describe line number
294-
# are always enough to derive what line numbers were added.
295-
git.fetch("origin", base_ref, "--depth=1000")
296-
diff = git.diff("--unified=0", "FETCH_HEAD", "--", ".")
297-
return parse_diff_output(diff)
298-
299-
300-
def parse_diff_output(diff: str) -> dict[pathlib.Path, list[int]]:
289+
def get_added_lines(diff: str) -> dict[pathlib.Path, list[int]]:
301290
current_file: pathlib.Path | None = None
302291
added_filename_prefix = "+++ b/"
303292
result: dict[pathlib.Path, list[int]] = {}

coverage_comment/github.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,27 @@ def append_to_file(content: str, filepath: pathlib.Path):
254254

255255
def add_job_summary(content: str, github_step_summary: pathlib.Path):
256256
append_to_file(content=content, filepath=github_step_summary)
257+
258+
259+
def get_pr_diff(github: github_client.GitHub, repository: str, pr_number: int) -> str:
260+
"""
261+
Get the diff of a pull request.
262+
"""
263+
return (
264+
github.repos(repository)
265+
.pulls(pr_number)
266+
.get(headers={"Accept": "application/vnd.github.v3.diff"})
267+
)
268+
269+
270+
def get_branch_diff(
271+
github: github_client.GitHub, repository: str, base_branch: str, head_branch: str
272+
) -> str:
273+
"""
274+
Get the diff of branch.
275+
"""
276+
return (
277+
github.repos(repository)
278+
.compare(f"{base_branch}...{head_branch}")
279+
.get(headers={"Accept": "application/vnd.github.v3.diff"})
280+
)

coverage_comment/github_client.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,7 @@ def _http(
8383
**header_kwargs,
8484
**requests_kwargs,
8585
)
86-
if bytes:
87-
contents = response.content
88-
else:
89-
contents = response_contents(response)
86+
contents = response_contents(response=response, bytes=bytes)
9087

9188
try:
9289
response.raise_for_status()
@@ -103,14 +100,15 @@ def _http(
103100

104101
def response_contents(
105102
response: httpx.Response,
103+
bytes: bool,
106104
) -> JsonObject | str | bytes:
105+
if bytes:
106+
return response.content
107+
107108
if response.headers.get("content-type", "").startswith("application/json"):
108109
return response.json(object_hook=JsonObject)
109-
if response.headers.get("content-type", "").startswith(
110-
"application/vnd.github.raw+json"
111-
):
112-
return response.text
113-
return response.content
110+
111+
return response.text
114112

115113

116114
class JsonObject(dict):

coverage_comment/main.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,20 @@ def process_pr(
132132
)
133133
base_ref = config.GITHUB_BASE_REF or repo_info.default_branch
134134

135-
added_lines = coverage_module.get_added_lines(git=git, base_ref=base_ref)
135+
if config.GITHUB_BRANCH_NAME:
136+
diff = github.get_branch_diff(
137+
github=gh,
138+
repository=config.GITHUB_REPOSITORY,
139+
base_branch=base_ref,
140+
head_branch=config.GITHUB_BRANCH_NAME,
141+
)
142+
elif config.GITHUB_PR_NUMBER:
143+
diff = github.get_pr_diff(
144+
github=gh,
145+
repository=config.GITHUB_REPOSITORY,
146+
pr_number=config.GITHUB_PR_NUMBER,
147+
)
148+
added_lines = coverage_module.get_added_lines(diff=diff)
136149
diff_coverage = coverage_module.get_diff_coverage_info(
137150
coverage=coverage, added_lines=added_lines
138151
)

tests/integration/conftest.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
from __future__ import annotations
2+
3+
import os
4+
import pathlib
5+
import subprocess
6+
import uuid
7+
8+
import pytest
9+
10+
11+
@pytest.fixture
12+
def in_integration_env(integration_env, integration_dir):
13+
curdir = os.getcwd()
14+
os.chdir(integration_dir)
15+
yield integration_dir
16+
os.chdir(curdir)
17+
18+
19+
@pytest.fixture
20+
def integration_dir(tmp_path: pathlib.Path):
21+
test_dir = tmp_path / "integration_test"
22+
test_dir.mkdir()
23+
return test_dir
24+
25+
26+
@pytest.fixture
27+
def file_path(integration_dir):
28+
return integration_dir / "foo.py"
29+
30+
31+
@pytest.fixture
32+
def write_file(file_path):
33+
def _(*variables):
34+
content = "import os"
35+
for i, var in enumerate(variables):
36+
content += f"""\nif os.environ.get("{var}"):\n {i}\n"""
37+
file_path.write_text(content, encoding="utf8")
38+
39+
return _
40+
41+
42+
@pytest.fixture
43+
def run_coverage(file_path, integration_dir):
44+
def _(*variables):
45+
subprocess.check_call(
46+
["coverage", "run", "--parallel", file_path.name],
47+
cwd=integration_dir,
48+
env=os.environ | dict.fromkeys(variables, "1"),
49+
)
50+
51+
return _
52+
53+
54+
@pytest.fixture
55+
def commit(integration_dir):
56+
def _():
57+
subprocess.check_call(
58+
["git", "add", "."],
59+
cwd=integration_dir,
60+
)
61+
subprocess.check_call(
62+
["git", "commit", "-m", str(uuid.uuid4())],
63+
cwd=integration_dir,
64+
env={
65+
"GIT_AUTHOR_NAME": "foo",
66+
"GIT_AUTHOR_EMAIL": "foo",
67+
"GIT_COMMITTER_NAME": "foo",
68+
"GIT_COMMITTER_EMAIL": "foo",
69+
"GIT_CONFIG_GLOBAL": "/dev/null",
70+
"GIT_CONFIG_SYSTEM": "/dev/null",
71+
},
72+
)
73+
74+
return _
75+
76+
77+
@pytest.fixture
78+
def integration_env(integration_dir, write_file, run_coverage, commit, request):
79+
subprocess.check_call(["git", "init", "-b", "main"], cwd=integration_dir)
80+
# diff coverage reads the "origin/{...}" branch so we simulate an origin remote
81+
subprocess.check_call(["git", "remote", "add", "origin", "."], cwd=integration_dir)
82+
write_file("A", "B")
83+
commit()
84+
85+
add_branch_mark = request.node.get_closest_marker("add_branches")
86+
for additional_branch in add_branch_mark.args if add_branch_mark else []:
87+
subprocess.check_call(
88+
["git", "switch", "-c", additional_branch],
89+
cwd=integration_dir,
90+
)
91+
92+
subprocess.check_call(
93+
["git", "switch", "-c", "branch"],
94+
cwd=integration_dir,
95+
)
96+
97+
write_file("A", "B", "C", "D")
98+
commit()
99+
100+
run_coverage("A", "C")
101+
subprocess.check_call(["git", "fetch", "origin"], cwd=integration_dir)

tests/integration/test_github.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,3 +444,29 @@ def test_annotations(capsys):
444444
::endgroup::"""
445445
output = capsys.readouterr()
446446
assert output.err.strip() == expected
447+
448+
449+
def test_get_pr_diff(gh, session):
450+
session.register(
451+
"GET",
452+
"/repos/foo/bar/pulls/123",
453+
headers={"Accept": "application/vnd.github.v3.diff"},
454+
)(text="diff --git a/foo.py b/foo.py...")
455+
456+
result = github.get_pr_diff(github=gh, repository="foo/bar", pr_number=123)
457+
458+
assert result == "diff --git a/foo.py b/foo.py..."
459+
460+
461+
def test_get_branch_diff(gh, session):
462+
session.register(
463+
"GET",
464+
"/repos/foo/bar/compare/main...feature",
465+
headers={"Accept": "application/vnd.github.v3.diff"},
466+
)(text="diff --git a/foo.py b/foo.py...")
467+
468+
result = github.get_branch_diff(
469+
github=gh, repository="foo/bar", base_branch="main", head_branch="feature"
470+
)
471+
472+
assert result == "diff --git a/foo.py b/foo.py..."

0 commit comments

Comments
 (0)