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
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ jobs:
contents: write
steps:
- uses: actions/checkout@v4
with:
# New lines are discovered by running a three-dot notation diff on base_ref...head. They must share a common
# ancestor. Setting fetch-depth to 1000 here should ensure that.
fetch-depth: 1000
Comment on lines +119 to +122
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll look into the e2e tests to test this since I'm not entirely sure how the actions/checkout action handles this. I wonder if you can get away with not setting fetch_depth here since a git fetch is called later.

Copy link
Member

Choose a reason for hiding this comment

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

Oooooh, that's the comment I missed that caused the issue. I'm sorry @stickperson I completely missed that 😅


- name: Install everything, run the tests, produce the .coverage file
run: make test # This is the part where you put your own test command
Expand Down Expand Up @@ -205,6 +209,8 @@ jobs:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1000

- name: Install everything, run the tests, produce the .coverage file
run: make test # This is the part where you put your own test command
Expand Down Expand Up @@ -247,6 +253,8 @@ jobs:

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1000

- name: Set up Python
id: setup-python
Expand Down Expand Up @@ -284,6 +292,8 @@ jobs:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1000

- uses: actions/download-artifact@v4
id: download
Expand Down
2 changes: 1 addition & 1 deletion coverage_comment/coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ def get_added_lines(
# don't merge chunks. This means the headers that describe line number
# are always enough to derive what line numbers were added.
git.fetch("origin", base_ref, "--depth=1000")
diff = git.diff("--unified=0", "FETCH_HEAD", "--", ".")
diff = git.diff("--unified=0", "FETCH_HEAD...HEAD")
return parse_diff_output(diff)


Expand Down
101 changes: 101 additions & 0 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from __future__ import annotations

import os
import pathlib
import subprocess
import uuid

import pytest


@pytest.fixture
Copy link
Member

Choose a reason for hiding this comment

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

This and below seems to be copied from test_main, right ?

Could you deduplicate it ? It's ok to move it here, but delete the corresponding copied code from test_main

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good call. Removed from test_main

def in_integration_env(integration_env, integration_dir):
curdir = os.getcwd()
os.chdir(integration_dir)
yield integration_dir
os.chdir(curdir)


@pytest.fixture
def integration_dir(tmp_path: pathlib.Path):
test_dir = tmp_path / "integration_test"
test_dir.mkdir()
return test_dir


@pytest.fixture
def file_path(integration_dir):
return integration_dir / "foo.py"


@pytest.fixture
def write_file(file_path):
def _(*variables):
content = "import os"
for i, var in enumerate(variables):
content += f"""\nif os.environ.get("{var}"):\n {i}\n"""
file_path.write_text(content, encoding="utf8")

return _


@pytest.fixture
def run_coverage(file_path, integration_dir):
def _(*variables):
subprocess.check_call(
["coverage", "run", "--parallel", file_path.name],
cwd=integration_dir,
env=os.environ | dict.fromkeys(variables, "1"),
)

return _


@pytest.fixture
def commit(integration_dir):
def _():
subprocess.check_call(
["git", "add", "."],
cwd=integration_dir,
)
subprocess.check_call(
["git", "commit", "-m", str(uuid.uuid4())],
cwd=integration_dir,
env={
"GIT_AUTHOR_NAME": "foo",
"GIT_AUTHOR_EMAIL": "foo",
"GIT_COMMITTER_NAME": "foo",
"GIT_COMMITTER_EMAIL": "foo",
"GIT_CONFIG_GLOBAL": "/dev/null",
"GIT_CONFIG_SYSTEM": "/dev/null",
},
)

return _


@pytest.fixture
def integration_env(integration_dir, write_file, run_coverage, commit, request):
subprocess.check_call(["git", "init", "-b", "main"], cwd=integration_dir)
# diff coverage reads the "origin/{...}" branch so we simulate an origin remote
subprocess.check_call(["git", "remote", "add", "origin", "."], cwd=integration_dir)
write_file("A", "B")
commit()

add_branch_mark = request.node.get_closest_marker("add_branches")
for additional_branch in add_branch_mark.args if add_branch_mark else []:
subprocess.check_call(
["git", "switch", "-c", additional_branch],
cwd=integration_dir,
)

subprocess.check_call(
["git", "switch", "-c", "branch"],
cwd=integration_dir,
)

write_file("A", "B", "C", "D")
commit()

run_coverage("A", "C")
subprocess.check_call(["git", "fetch", "origin"], cwd=integration_dir)
30 changes: 30 additions & 0 deletions tests/integration/test_coverage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from __future__ import annotations

import subprocess

from coverage_comment import coverage
from coverage_comment import subprocess as subprocess_module


def test_get_added_lines(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't believe this is strictly necessary as it's more testing git than get_added_lines. I'm happy to take it out.

Copy link
Member

Choose a reason for hiding this comment

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

I'm good keeping it :)

commit, file_path, integration_dir, in_integration_env, write_file
):
"""
Lines added in the base_ref should not appear as added in HEAD
"""
git = subprocess_module.Git()
relative_file_path = file_path.relative_to(integration_dir)

assert coverage.get_added_lines(git, "main") == {
relative_file_path: list(range(7, 13)) # Line numbers start at 1
}

subprocess.check_call(["git", "switch", "main"], cwd=integration_dir)
write_file("E", "F")
commit()
subprocess.check_call(["git", "push", "origin", "main"], cwd=integration_dir)
subprocess.check_call(["git", "switch", "branch"], cwd=integration_dir)

assert coverage.get_added_lines(git, "main") == {
relative_file_path: list(range(7, 13)) # Line numbers start at 1
}
115 changes: 9 additions & 106 deletions tests/integration/test_main.py
Original file line number Diff line number Diff line change
@@ -1,59 +1,12 @@
from __future__ import annotations

import json
import os
import pathlib
import subprocess
import uuid

import pytest

from coverage_comment import main


@pytest.fixture
def in_integration_env(integration_env, integration_dir):
curdir = os.getcwd()
os.chdir(integration_dir)
yield integration_dir
os.chdir(curdir)


@pytest.fixture
def integration_dir(tmp_path: pathlib.Path):
test_dir = tmp_path / "integration_test"
test_dir.mkdir()
return test_dir


@pytest.fixture
def file_path(integration_dir):
return integration_dir / "foo.py"


@pytest.fixture
def write_file(file_path):
def _(*variables):
content = "import os"
for i, var in enumerate(variables):
content += f"""\nif os.environ.get("{var}"):\n {i}\n"""
file_path.write_text(content, encoding="utf8")

return _


@pytest.fixture
def run_coverage(file_path, integration_dir):
def _(*variables):
subprocess.check_call(
["coverage", "run", "--parallel", file_path.name],
cwd=integration_dir,
env=os.environ | dict.fromkeys(variables, "1"),
)

return _


DIFF_STDOUT = """diff --git a/foo.py b/foo.py
index 6c08c94..b65c612 100644
--- a/foo.py
Expand All @@ -68,56 +21,6 @@ def _(*variables):
"""


@pytest.fixture
def commit(integration_dir):
def _():
subprocess.check_call(
["git", "add", "."],
cwd=integration_dir,
)
subprocess.check_call(
["git", "commit", "-m", str(uuid.uuid4())],
cwd=integration_dir,
env={
"GIT_AUTHOR_NAME": "foo",
"GIT_AUTHOR_EMAIL": "foo",
"GIT_COMMITTER_NAME": "foo",
"GIT_COMMITTER_EMAIL": "foo",
"GIT_CONFIG_GLOBAL": "/dev/null",
"GIT_CONFIG_SYSTEM": "/dev/null",
},
)

return _


@pytest.fixture
def integration_env(integration_dir, write_file, run_coverage, commit, request):
subprocess.check_call(["git", "init", "-b", "main"], cwd=integration_dir)
# diff coverage reads the "origin/{...}" branch so we simulate an origin remote
subprocess.check_call(["git", "remote", "add", "origin", "."], cwd=integration_dir)
write_file("A", "B")
commit()

add_branch_mark = request.node.get_closest_marker("add_branches")
for additional_branch in add_branch_mark.args if add_branch_mark else []:
subprocess.check_call(
["git", "switch", "-c", additional_branch],
cwd=integration_dir,
)

subprocess.check_call(
["git", "switch", "-c", "branch"],
cwd=integration_dir,
)

write_file("A", "B", "C", "D")
commit()

run_coverage("A", "C")
subprocess.check_call(["git", "fetch", "origin"], cwd=integration_dir)


def test_action__invalid_event_name(session, push_config, in_integration_env, get_logs):
session.register("GET", "/repos/py-cov-action/foobar")(
json={"default_branch": "main", "visibility": "public"}
Expand Down Expand Up @@ -172,7 +75,7 @@ def checker(payload):
)(status_code=403)

git.register("git fetch origin main --depth=1000")()
git.register("git diff --unified=0 FETCH_HEAD -- .")(stdout=DIFF_STDOUT)
git.register("git diff --unified=0 FETCH_HEAD...HEAD")(stdout=DIFF_STDOUT)

result = main.action(
config=pull_request_config(
Expand Down Expand Up @@ -253,7 +156,7 @@ def checker(payload):
)(status_code=403)

git.register("git fetch origin foo --depth=1000")(stdout=DIFF_STDOUT)
git.register("git diff --unified=0 FETCH_HEAD -- .")(stdout=DIFF_STDOUT)
git.register("git diff --unified=0 FETCH_HEAD...HEAD")(stdout=DIFF_STDOUT)

result = main.action(
config=pull_request_config(
Expand Down Expand Up @@ -300,7 +203,7 @@ def test_action__pull_request__post_comment(
session.register("GET", "/repos/py-cov-action/foobar/issues/2/comments")(json=[])

git.register("git fetch origin main --depth=1000")()
git.register("git diff --unified=0 FETCH_HEAD -- .")(stdout=DIFF_STDOUT)
git.register("git diff --unified=0 FETCH_HEAD...HEAD")(stdout=DIFF_STDOUT)

comment = None

Expand Down Expand Up @@ -347,7 +250,7 @@ def test_action__push__non_default_branch(
json={"default_branch": "main", "visibility": "public"}
)
git.register("git fetch origin main --depth=1000")(stdout=DIFF_STDOUT)
git.register("git diff --unified=0 FETCH_HEAD -- .")(stdout=DIFF_STDOUT)
git.register("git diff --unified=0 FETCH_HEAD...HEAD")(stdout=DIFF_STDOUT)

payload = json.dumps({"coverage": 30.00})
# There is an existing badge in this test, allowing to test the coverage evolution
Expand Down Expand Up @@ -436,7 +339,7 @@ def test_action__push__non_default_branch__no_pr(
json={"default_branch": "main", "visibility": "public"}
)
git.register("git fetch origin main --depth=1000")(stdout=DIFF_STDOUT)
git.register("git diff --unified=0 FETCH_HEAD -- .")(stdout=DIFF_STDOUT)
git.register("git diff --unified=0 FETCH_HEAD...HEAD")(stdout=DIFF_STDOUT)

payload = json.dumps({"coverage": 30.00})
# There is an existing badge in this test, allowing to test the coverage evolution
Expand Down Expand Up @@ -500,7 +403,7 @@ def test_action__pull_request__force_store_comment(
)(text=payload, headers={"content-type": "application/vnd.github.raw+json"})

git.register("git fetch origin main --depth=1000")()
git.register("git diff --unified=0 FETCH_HEAD -- .")(stdout=DIFF_STDOUT)
git.register("git diff --unified=0 FETCH_HEAD...HEAD")(stdout=DIFF_STDOUT)

result = main.action(
config=pull_request_config(FORCE_WORKFLOW_RUN=True, GITHUB_OUTPUT=output_file),
Expand Down Expand Up @@ -531,7 +434,7 @@ def test_action__pull_request__post_comment__no_marker(
)(status_code=404)

git.register("git fetch origin main --depth=1000")()
git.register("git diff --unified=0 FETCH_HEAD -- .")(stdout=DIFF_STDOUT)
git.register("git diff --unified=0 FETCH_HEAD...HEAD")(stdout=DIFF_STDOUT)

result = main.action(
config=pull_request_config(COMMENT_TEMPLATE="""foo"""),
Expand All @@ -556,7 +459,7 @@ def test_action__pull_request__annotations(
)(status_code=404)

git.register("git fetch origin main --depth=1000")()
git.register("git diff --unified=0 FETCH_HEAD -- .")(stdout=DIFF_STDOUT)
git.register("git diff --unified=0 FETCH_HEAD...HEAD")(stdout=DIFF_STDOUT)

# Who am I
session.register("GET", "/user")(json={"login": "foo"})
Expand Down Expand Up @@ -598,7 +501,7 @@ def test_action__pull_request__post_comment__template_error(
)(status_code=404)

git.register("git fetch origin main --depth=1000")()
git.register("git diff --unified=0 FETCH_HEAD -- .")(stdout=DIFF_STDOUT)
git.register("git diff --unified=0 FETCH_HEAD...HEAD")(stdout=DIFF_STDOUT)

result = main.action(
config=pull_request_config(COMMENT_TEMPLATE="""{%"""),
Expand Down
Loading
Loading