Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 58cf604

Browse files
aj3shAjesh Sen Thapa
and
Ajesh Sen Thapa
authored
test: add tests for github actions with coverage (#66)
Co-authored-by: Ajesh Sen Thapa <ast@logpoint.com>
1 parent dffb36b commit 58cf604

18 files changed

+848
-10
lines changed

‎Pipfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pytest-cov = "*"
1212

1313
[scripts]
1414
test = "pytest"
15-
coverage = "pytest --cov=src/ --no-cov-on-fail"
16-
coverage-html = "pytest --cov=src/ --cov-report=html --no-cov-on-fail"
17-
coverage-xml = "pytest --cov=src/ --cov-report=xml --no-cov-on-fail"
15+
coverage = "pytest --cov=src --cov=github_actions"
16+
coverage-html = "pytest --cov=src --cov=github_actions --cov-report=html"
17+
coverage-xml = "pytest --cov=src --cov=github_actions --cov-report=xml"
1818
install-hooks = "pre-commit install --hook-type pre-commit --hook-type commit-msg"

‎github_actions/__main__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""Main entry point for the GitHub Actions workflow."""
22

3-
from action.run import run_action
3+
from action.run import run_action# pragma: no cover
44

5-
run_action()
5+
run_action()# pragma: no cover

‎github_actions/action/run.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import os
77
import subprocess
88
import sys
9-
from math import ceil
109
from typing import Iterable, List, Optional, Tuple, cast
1110

1211
from .event import GitHubEvent
@@ -33,6 +32,7 @@
3332
STATUS_FAILURE = "failure"
3433

3534
MAX_PR_COMMITS = 250
35+
PER_PAGE_COMMITS = 50
3636

3737

3838
def get_push_commit_messages(event: GitHubEvent) -> Iterable[str]:
@@ -75,16 +75,15 @@ def get_pr_commit_messages(event: GitHubEvent) -> Iterable[str]:
7575
)
7676

7777
# pagination
78-
per_page = 50
79-
total_page = ceil(total_commits / per_page)
78+
total_page = 1 + total_commits // PER_PAGE_COMMITS
8079

8180
commits: List[str] = []
8281
for page in range(1, total_page + 1):
8382
status, data = request_github_api(
8483
method="GET",
8584
url=f"/repos/{repo}/pulls/{pr_number}/commits",
8685
token=token,
87-
params={"per_page": per_page, "page": page},
86+
params={"per_page": PER_PAGE_COMMITS, "page": page},
8887
)
8988

9089
if status != 200:

‎pytest.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[pytest]
2-
pythonpath = src
2+
pythonpath = . src
33
python_files = test_*.py
44
addopts = -vvv

‎tests/fixtures/actions_env.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# type: ignore
2+
# pylint: disable=all
3+
import os
4+
5+
6+
def set_github_env_vars():
7+
# GitHub Action event env
8+
os.environ["GITHUB_EVENT_NAME"] = "push"
9+
os.environ["GITHUB_SHA"] = "commitlint_sha"
10+
os.environ["GITHUB_REF"] = "refs/heads/main"
11+
os.environ["GITHUB_WORKFLOW"] = "commitlint_ci"
12+
os.environ["GITHUB_ACTION"] = "action"
13+
os.environ["GITHUB_ACTOR"] = "actor"
14+
os.environ["GITHUB_REPOSITORY"] = "opensource-nepal/commitlint"
15+
os.environ["GITHUB_JOB"] = "job"
16+
os.environ["GITHUB_RUN_ATTEMPT"] = "9"
17+
os.environ["GITHUB_RUN_NUMBER"] = "8"
18+
os.environ["GITHUB_RUN_ID"] = "7"
19+
os.environ["GITHUB_EVENT_PATH"] = "/tmp/github_event.json"
20+
os.environ["GITHUB_STEP_SUMMARY"] = "/tmp/github_step_summary"
21+
os.environ["GITHUB_OUTPUT"] = "/tmp/github_output"
22+
23+
# GitHub Action input env
24+
os.environ["INPUT_TOKEN"] = "token"
25+
os.environ["INPUT_VERBOSE"] = "false"
26+
os.environ["INPUT_FAIL_ON_ERROR"] = "true"

‎tests/test_github_actions/test_event.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# type: ignore
2+
# pylint: disable=all
3+
4+
import json
5+
import os
6+
from unittest.mock import mock_open, patch
7+
8+
import pytest
9+
10+
from github_actions.action.event import GitHubEvent
11+
from tests.fixtures.actions_env import set_github_env_vars
12+
13+
MOCK_PAYLOAD = {"key": "value"}
14+
15+
16+
@pytest.fixture(scope="module")
17+
def github_event():
18+
set_github_env_vars()
19+
with patch("builtins.open", mock_open(read_data=json.dumps(MOCK_PAYLOAD))):
20+
return GitHubEvent()
21+
22+
23+
def test__github_event__initialization(github_event):
24+
assert github_event.event_name == "push"
25+
assert github_event.sha == "commitlint_sha"
26+
assert github_event.ref == "refs/heads/main"
27+
assert github_event.workflow == "commitlint_ci"
28+
assert github_event.action == "action"
29+
assert github_event.actor == "actor"
30+
assert github_event.repository == "opensource-nepal/commitlint"
31+
assert github_event.job == "job"
32+
assert github_event.run_attempt == "9"
33+
assert github_event.run_number == "8"
34+
assert github_event.run_id == "7"
35+
assert github_event.event_path == "/tmp/github_event.json"
36+
assert github_event.payload == MOCK_PAYLOAD
37+
38+
39+
def test__github_event__to_dict(github_event):
40+
event_dict = github_event.to_dict()
41+
assert event_dict["event_name"] == "push"
42+
assert event_dict["sha"] == "commitlint_sha"
43+
assert event_dict["ref"] == "refs/heads/main"
44+
assert event_dict["workflow"] == "commitlint_ci"
45+
assert event_dict["action"] == "action"
46+
assert event_dict["actor"] == "actor"
47+
assert event_dict["repository"] == "opensource-nepal/commitlint"
48+
assert event_dict["job"] == "job"
49+
assert event_dict["run_attempt"] == "9"
50+
assert event_dict["run_number"] == "8"
51+
assert event_dict["run_id"] == "7"
52+
assert event_dict["event_path"] == "/tmp/github_event.json"
53+
assert event_dict["payload"] == MOCK_PAYLOAD
54+
55+
56+
def test__github_event__str(github_event):
57+
event_str = str(github_event)
58+
assert "push" in event_str
59+
assert "commitlint_sha" in event_str
60+
assert "refs/heads/main" in event_str
61+
assert "commitlint_ci" in event_str
62+
assert "action" in event_str
63+
assert "actor" in event_str
64+
assert "opensource-nepal/commitlint" in event_str
65+
assert "job" in event_str
66+
assert "9" in event_str
67+
68+
69+
def test__github_event__env_error():
70+
os.environ.pop("GITHUB_EVENT_NAME")
71+
with pytest.raises(EnvironmentError):
72+
GitHubEvent()
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# type: ignore
2+
# pylint: disable=all
3+
import os
4+
from unittest.mock import patch
5+
6+
import pytest
7+
8+
from github_actions.action.run import check_commit_messages
9+
from tests.fixtures.actions_env import set_github_env_vars
10+
11+
# Constants
12+
STATUS_SUCCESS = "success"
13+
STATUS_FAILURE = "failure"
14+
INPUT_FAIL_ON_ERROR = "fail_on_error"
15+
16+
17+
@pytest.fixture(scope="module", autouse=True)
18+
def setup_env():
19+
set_github_env_vars()
20+
21+
22+
@patch("github_actions.action.run.run_commitlint")
23+
@patch("github_actions.action.run.write_line_to_file")
24+
@patch("github_actions.action.run.write_output")
25+
@patch.dict(os.environ, {**os.environ, "GITHUB_STEP_SUMMARY": "summary_path"})
26+
def test__check_commit_messages__all_valid_messages(
27+
mock_write_output,
28+
mock_write_line_to_file,
29+
mock_run_commitlint,
30+
):
31+
commit_messages = ["feat: valid commit 1", "fix: valid commit 2"]
32+
mock_run_commitlint.return_value = (True, None)
33+
34+
check_commit_messages(commit_messages)
35+
36+
mock_run_commitlint.assert_any_call("feat: valid commit 1")
37+
mock_run_commitlint.assert_any_call("fix: valid commit 2")
38+
mock_write_line_to_file.assert_called_once_with(
39+
"summary_path", "commitlint: All commits passed!"
40+
)
41+
mock_write_output.assert_any_call("status", STATUS_SUCCESS)
42+
mock_write_output.assert_any_call("exit_code", 0)
43+
44+
45+
@patch("github_actions.action.run.run_commitlint")
46+
@patch("github_actions.action.run.write_line_to_file")
47+
@patch("github_actions.action.run.write_output")
48+
@patch.dict(os.environ, {**os.environ, "GITHUB_STEP_SUMMARY": "summary_path"})
49+
def test__check_commit_messages__partial_invalid_messages(
50+
mock_write_output,
51+
mock_write_line_to_file,
52+
mock_run_commitlint,
53+
):
54+
commit_messages = ["feat: valid commit", "invalid commit message"]
55+
mock_run_commitlint.side_effect = [
56+
(True, None),
57+
(False, "Error: invalid commit format"),
58+
]
59+
60+
with pytest.raises(SystemExit):
61+
check_commit_messages(commit_messages)
62+
63+
mock_run_commitlint.assert_any_call("feat: valid commit")
64+
mock_run_commitlint.assert_any_call("invalid commit message")
65+
mock_write_line_to_file.assert_called_once_with(
66+
"summary_path", "commitlint: 1 commit(s) failed!"
67+
)
68+
mock_write_output.assert_any_call("status", STATUS_FAILURE)
69+
mock_write_output.assert_any_call("exit_code", 1)
70+
71+
72+
@patch("github_actions.action.run.run_commitlint")
73+
@patch("github_actions.action.run.write_line_to_file")
74+
@patch("github_actions.action.run.write_output")
75+
@patch.dict(
76+
os.environ,
77+
{
78+
**os.environ,
79+
"GITHUB_STEP_SUMMARY": "summary_path",
80+
"INPUT_FAIL_ON_ERROR": "False",
81+
},
82+
)
83+
def test__check_commit_messages__fail_on_error_false(
84+
mock_write_output,
85+
mock_write_line_to_file,
86+
mock_run_commitlint,
87+
):
88+
commit_messages = ["invalid commit message"]
89+
mock_run_commitlint.return_value = (False, "Invalid commit format")
90+
91+
check_commit_messages(commit_messages)
92+
93+
mock_run_commitlint.assert_called_once_with("invalid commit message")
94+
mock_write_line_to_file.assert_called_once_with(
95+
"summary_path", "commitlint: 1 commit(s) failed!"
96+
)
97+
mock_write_output.assert_any_call("status", STATUS_FAILURE)
98+
mock_write_output.assert_any_call("exit_code", 1)
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# type: ignore
2+
# pylint: disable=all
3+
import json
4+
import os
5+
from unittest.mock import mock_open, patch
6+
7+
import pytest
8+
9+
from github_actions.action.event import GitHubEvent
10+
from github_actions.action.run import (
11+
MAX_PR_COMMITS,
12+
PER_PAGE_COMMITS,
13+
get_pr_commit_messages,
14+
)
15+
from tests.fixtures.actions_env import set_github_env_vars
16+
17+
18+
@pytest.fixture(scope="module", autouse=True)
19+
def setup_env():
20+
set_github_env_vars()
21+
22+
23+
@patch("github_actions.action.run.request_github_api")
24+
@patch.dict(os.environ, {**os.environ, "GITHUB_EVENT_NAME": "pull_request"})
25+
def test__get_pr_commit_messages__single_page(
26+
mock_request_github_api,
27+
):
28+
# mock github api request
29+
mock_request_github_api.return_value = (
30+
200,
31+
[{"commit": {"message": "feat: commit message"}}],
32+
)
33+
34+
payload = {"number": 10, "pull_request": {"commits": 2}}
35+
with patch("builtins.open", mock_open(read_data=json.dumps(payload))):
36+
event = GitHubEvent()
37+
result = get_pr_commit_messages(event)
38+
assert result == ["feat: commit message"]
39+
40+
mock_request_github_api.assert_called_once_with(
41+
method="GET",
42+
url="/repos/opensource-nepal/commitlint/pulls/10/commits",
43+
token="token",
44+
params={"per_page": PER_PAGE_COMMITS, "page": 1},
45+
)
46+
47+
48+
@patch("github_actions.action.run.request_github_api")
49+
@patch.dict(os.environ, {**os.environ, "GITHUB_EVENT_NAME": "pull_request"})
50+
def test__get_pr_commit_messages__multiple_page(
51+
mock_request_github_api,
52+
):
53+
# mock github api request
54+
mock_request_github_api.side_effect = [
55+
(
56+
200,
57+
[{"commit": {"message": "feat: commit message1"}}],
58+
),
59+
(
60+
200,
61+
[{"commit": {"message": "feat: commit message2"}}],
62+
),
63+
]
64+
65+
payload = {"number": 10, "pull_request": {"commits": 60}}
66+
with patch("builtins.open", mock_open(read_data=json.dumps(payload))):
67+
event = GitHubEvent()
68+
result = get_pr_commit_messages(event)
69+
assert result == ["feat: commit message1", "feat: commit message2"]
70+
71+
assert mock_request_github_api.call_count == 2
72+
mock_request_github_api.assert_any_call(
73+
method="GET",
74+
url="/repos/opensource-nepal/commitlint/pulls/10/commits",
75+
token="token",
76+
params={"per_page": PER_PAGE_COMMITS, "page": 1},
77+
)
78+
79+
mock_request_github_api.assert_any_call(
80+
method="GET",
81+
url="/repos/opensource-nepal/commitlint/pulls/10/commits",
82+
token="token",
83+
params={"per_page": PER_PAGE_COMMITS, "page": 2},
84+
)
85+
86+
87+
@patch("github_actions.action.run.request_github_api")
88+
@patch.dict(os.environ, {**os.environ, "GITHUB_EVENT_NAME": "pull_request"})
89+
def test__get_pr_commit_messages__api_failure(
90+
mock_request_github_api,
91+
):
92+
mock_request_github_api.return_value = (500, None)
93+
payload = {"number": 10, "pull_request": {"commits": 60}}
94+
with patch("builtins.open", mock_open(read_data=json.dumps(payload))):
95+
with pytest.raises(SystemExit):
96+
event = GitHubEvent()
97+
get_pr_commit_messages(event)
98+
99+
100+
@patch.dict(os.environ, {**os.environ, "GITHUB_EVENT_NAME": "pull_request"})
101+
def test__get_pr_commit_messages__exceed_max_commits():
102+
payload = {"number": 10, "pull_request": {"commits": MAX_PR_COMMITS + 1}}
103+
with patch("builtins.open", mock_open(read_data=json.dumps(payload))):
104+
with pytest.raises(SystemExit):
105+
event = GitHubEvent()
106+
get_pr_commit_messages(event)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# type: ignore
2+
# pylint: disable=all
3+
4+
import json
5+
from unittest.mock import mock_open, patch
6+
7+
import pytest
8+
9+
from github_actions.action.event import GitHubEvent
10+
from github_actions.action.run import get_push_commit_messages
11+
from tests.fixtures.actions_env import set_github_env_vars
12+
13+
14+
@pytest.fixture(scope="module", autouse=True)
15+
def setup_env():
16+
set_github_env_vars()
17+
18+
19+
def test__get_push_commit_messages__returns_push_commits():
20+
payload = {
21+
"commits": [
22+
{"message": "feat: valid message"},
23+
{"message": "fix(login): fix login message"},
24+
]
25+
}
26+
with patch("builtins.open", mock_open(read_data=json.dumps(payload))):
27+
commits = get_push_commit_messages(GitHubEvent())
28+
assert list(commits) == ["feat: valid message", "fix(login): fix login message"]

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /