Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 58cf604

Browse files
aj3shAjesh Sen Thapa
and
Ajesh Sen Thapa
authoredAug 30, 2024··
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"
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"]
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# type: ignore
2+
# pylint: disable=all
3+
"""
4+
Integration test of `run.py` to ensure Github Action full functionality.
5+
"""
6+
7+
import json
8+
import os
9+
import subprocess
10+
from unittest.mock import call, mock_open, patch
11+
12+
import pytest
13+
14+
from github_actions.action.run import run_action
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("subprocess.check_output", return_value="success")
24+
@patch.dict(os.environ, {**os.environ, "GITHUB_EVENT_NAME": "push"})
25+
def test__run_action__push_event_full_integration_test_for_valid_commits(
26+
mock_check_output,
27+
):
28+
payload = {
29+
"commits": [
30+
{"message": "feat: valid message"},
31+
{"message": "fix(login): fix login message"},
32+
]
33+
}
34+
with patch("builtins.open", mock_open(read_data=json.dumps(payload))):
35+
run_action()
36+
37+
assert mock_check_output.call_count == 2
38+
expected_calls = [
39+
call(
40+
["commitlint", "feat: valid message", "--hide-input"],
41+
text=True,
42+
stderr=subprocess.PIPE,
43+
),
44+
call(
45+
["commitlint", "fix(login): fix login message", "--hide-input"],
46+
text=True,
47+
stderr=subprocess.PIPE,
48+
),
49+
]
50+
mock_check_output.assert_has_calls(expected_calls, any_order=False)
51+
52+
53+
@patch("subprocess.check_output", return_value="success")
54+
@patch.dict(os.environ, {**os.environ, "GITHUB_EVENT_NAME": "push"})
55+
def test__run_action__push_event_full_integration_test_for_invalid_commits(
56+
mock_check_output,
57+
):
58+
# mock for commitlint command to return error
59+
mock_check_output.side_effect = subprocess.CalledProcessError(
60+
1, ["cmd"], "stdout", "stderr"
61+
)
62+
63+
payload = {
64+
"commits": [
65+
{"message": "feat: valid message"},
66+
{"message": "invalid commit message"},
67+
]
68+
}
69+
with patch("builtins.open", mock_open(read_data=json.dumps(payload))):
70+
with pytest.raises(SystemExit):
71+
run_action()
72+
73+
assert mock_check_output.call_count == 2
74+
expected_calls = [
75+
call(
76+
["commitlint", "feat: valid message", "--hide-input"],
77+
text=True,
78+
stderr=subprocess.PIPE,
79+
),
80+
call(
81+
["commitlint", "invalid commit message", "--hide-input"],
82+
text=True,
83+
stderr=subprocess.PIPE,
84+
),
85+
]
86+
mock_check_output.assert_has_calls(expected_calls, any_order=False)
87+
88+
89+
@patch("github_actions.action.run.request_github_api")
90+
@patch("subprocess.check_output", return_value="success")
91+
@patch.dict(os.environ, {**os.environ, "GITHUB_EVENT_NAME": "pull_request"})
92+
def test__run_action__pr_event_full_integration_test_for_valid_commits(
93+
mock_check_output,
94+
mock_request_github_api,
95+
):
96+
# mock github api request
97+
mock_request_github_api.return_value = (
98+
200,
99+
[
100+
{
101+
"commit": {"message": "feat: valid message"},
102+
},
103+
{
104+
"commit": {"message": "fix(login): fix login message"},
105+
},
106+
],
107+
)
108+
109+
payload = {"number": 10, "pull_request": {"commits": 2}}
110+
with patch("builtins.open", mock_open(read_data=json.dumps(payload))):
111+
run_action()
112+
113+
assert mock_check_output.call_count == 2
114+
expected_calls = [
115+
call(
116+
["commitlint", "feat: valid message", "--hide-input"],
117+
text=True,
118+
stderr=subprocess.PIPE,
119+
),
120+
call(
121+
["commitlint", "fix(login): fix login message", "--hide-input"],
122+
text=True,
123+
stderr=subprocess.PIPE,
124+
),
125+
]
126+
mock_check_output.assert_has_calls(expected_calls, any_order=False)
127+
128+
129+
@patch("github_actions.action.run.request_github_api")
130+
@patch("subprocess.check_output", return_value="success")
131+
@patch.dict(os.environ, {**os.environ, "GITHUB_EVENT_NAME": "pull_request"})
132+
def test__run_action__pr_event_full_integration_test_for_invalid_commits(
133+
mock_check_output,
134+
mock_request_github_api,
135+
):
136+
# mock for commitlint command to return error
137+
mock_check_output.side_effect = subprocess.CalledProcessError(
138+
1, ["cmd"], "stdout", "stderr"
139+
)
140+
141+
# mock github api request
142+
mock_request_github_api.return_value = (
143+
200,
144+
[
145+
{
146+
"commit": {"message": "feat: valid message"},
147+
},
148+
{
149+
"commit": {"message": "invalid commit message"},
150+
},
151+
],
152+
)
153+
154+
payload = {"number": 10, "pull_request": {"commits": 2}}
155+
with patch("builtins.open", mock_open(read_data=json.dumps(payload))):
156+
with pytest.raises(SystemExit):
157+
run_action()
158+
159+
assert mock_check_output.call_count == 2
160+
expected_calls = [
161+
call(
162+
["commitlint", "feat: valid message", "--hide-input"],
163+
text=True,
164+
stderr=subprocess.PIPE,
165+
),
166+
call(
167+
["commitlint", "invalid commit message", "--hide-input"],
168+
text=True,
169+
stderr=subprocess.PIPE,
170+
),
171+
]
172+
mock_check_output.assert_has_calls(expected_calls, any_order=False)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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 github_actions.action.run import run_action
12+
from tests.fixtures.actions_env import set_github_env_vars
13+
14+
15+
@pytest.fixture(scope="module", autouse=True)
16+
def setup_env():
17+
set_github_env_vars()
18+
19+
20+
@pytest.fixture(autouse=True)
21+
def mock_open_file():
22+
with patch("builtins.open", mock_open(read_data=json.dumps({}))) as mocked_open:
23+
yield mocked_open
24+
25+
26+
@patch("github_actions.action.run._handle_push_event")
27+
@patch.dict(os.environ, {**os.environ, "GITHUB_EVENT_NAME": "push"})
28+
def test__run_action__calls_handle_push_events(mock_handle_push_event):
29+
run_action()
30+
mock_handle_push_event.assert_called_once()
31+
args, _ = mock_handle_push_event.call_args
32+
assert type(args[0]) == GitHubEvent
33+
assert args[0].event_name == "push"
34+
35+
36+
@patch("github_actions.action.run._handle_pr_event")
37+
@patch.dict(os.environ, {**os.environ, "GITHUB_EVENT_NAME": "pull_request"})
38+
def test__run_action__calls_handle_pr_events(mock_handle_pr_event):
39+
run_action()
40+
mock_handle_pr_event.assert_called_once()
41+
args, _ = mock_handle_pr_event.call_args
42+
assert type(args[0]) == GitHubEvent
43+
assert args[0].event_name == "pull_request"
44+
45+
46+
@patch("github_actions.action.run._handle_pr_event")
47+
@patch.dict(os.environ, {**os.environ, "GITHUB_EVENT_NAME": "pull_request_target"})
48+
def test__run_action__calls_handle_pr_events_for_pull_request_target(
49+
mock_handle_pr_event,
50+
):
51+
run_action()
52+
mock_handle_pr_event.assert_called_once()
53+
args, _ = mock_handle_pr_event.call_args
54+
assert type(args[0]) == GitHubEvent
55+
assert args[0].event_name == "pull_request_target"
56+
57+
58+
@patch("sys.stdout.write")
59+
@patch.dict(os.environ, {**os.environ, "GITHUB_EVENT_NAME": "workflow_dispatch"})
60+
def test__run_action__skips_unknown_event(mock_stdout_write):
61+
run_action()
62+
mock_stdout_write.assert_called_once_with("Skipping for event workflow_dispatch\n")
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# type: ignore
2+
# pylint: disable=all
3+
import os
4+
import subprocess
5+
from unittest.mock import patch
6+
7+
from github_actions.action.run import run_commitlint
8+
9+
10+
@patch("subprocess.check_output", return_value="feat: valid commit message")
11+
@patch.dict(os.environ, {**os.environ, "INPUT_VERBOSE": "False"})
12+
def test__run_commitlint__success(mock_check_output):
13+
commit_message = "feat: add new feature"
14+
15+
result = run_commitlint(commit_message)
16+
17+
assert result == (True, None)
18+
mock_check_output.assert_called_once_with(
19+
["commitlint", commit_message, "--hide-input"],
20+
text=True,
21+
stderr=subprocess.PIPE,
22+
)
23+
24+
25+
@patch("subprocess.check_output")
26+
@patch.dict(os.environ, {**os.environ, "INPUT_VERBOSE": "False"})
27+
def test__run_commitlint__failure(mock_check_output):
28+
mock_check_output.side_effect = (
29+
subprocess.CalledProcessError(1, "cmd", output="", stderr="Error"),
30+
)
31+
32+
commit_message = "invalid commit message"
33+
result = run_commitlint(commit_message)
34+
35+
assert result == (False, "Error")
36+
mock_check_output.assert_called_once_with(
37+
["commitlint", commit_message, "--hide-input"],
38+
text=True,
39+
stderr=subprocess.PIPE,
40+
)
41+
42+
43+
@patch(
44+
"subprocess.check_output",
45+
return_value="feat: valid commit message",
46+
)
47+
@patch.dict(os.environ, {**os.environ, "INPUT_VERBOSE": "True"})
48+
def test__run_commitlint__verbose(mock_check_output):
49+
commit_message = "feat: add new feature"
50+
51+
result = run_commitlint(commit_message)
52+
53+
assert result == (True, None)
54+
mock_check_output.assert_called_once_with(
55+
["commitlint", commit_message, "--hide-input", "--verbose"],
56+
text=True,
57+
stderr=subprocess.PIPE,
58+
)
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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.utils import get_boolean_input
9+
10+
11+
@patch.dict(os.environ, {"INPUT_TEST": "True"})
12+
def test__get_boolean_input__return_True_for_True():
13+
assert get_boolean_input("test") is True
14+
15+
16+
@patch.dict(os.environ, {"INPUT_TEST": "TRUE"})
17+
def test__get_boolean_input__return_True_for_TRUE():
18+
assert get_boolean_input("test") is True
19+
20+
21+
@patch.dict(os.environ, {"INPUT_TEST": "true"})
22+
def test__get_boolean_input__return_True_for_true():
23+
assert get_boolean_input("test") is True
24+
25+
26+
@patch.dict(os.environ, {"INPUT_TEST": "False"})
27+
def test__get_boolean_input__return_False_for_False():
28+
assert get_boolean_input("test") is False
29+
30+
31+
@patch.dict(os.environ, {"INPUT_TEST": "FALSE"})
32+
def test__get_boolean_input__return_False_for_FALSE():
33+
assert get_boolean_input("test") is False
34+
35+
36+
@patch.dict(os.environ, {"INPUT_TEST": "false"})
37+
def test__get_boolean_input__return_False_for_false():
38+
assert get_boolean_input("test") is False
39+
40+
41+
@patch.dict(os.environ, {"INPUT_TEST": "random"})
42+
def test__get_boolean_input__raises_type_error_for_unknown():
43+
with pytest.raises(TypeError):
44+
get_boolean_input("test")
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# type: ignore
2+
# pylint: disable=all
3+
import os
4+
from unittest.mock import patch
5+
6+
from github_actions.action.utils import get_input
7+
8+
9+
def test_get_input_variable_set():
10+
with patch.dict(os.environ, {"INPUT_TEST": "value"}):
11+
assert get_input("test") == "value"
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# type: ignore
2+
# pylint: disable=all
3+
import json
4+
from unittest.mock import Mock, patch
5+
6+
import pytest
7+
8+
from github_actions.action.utils import request_github_api
9+
10+
11+
@pytest.fixture
12+
def mock_https_connection():
13+
with patch("http.client.HTTPSConnection") as mock:
14+
mock_response = Mock()
15+
mock_response.read.return_value = json.dumps({"success": True}).encode("utf-8")
16+
mock_response.status = 200
17+
mock.return_value.getresponse.return_value = mock_response
18+
19+
yield mock
20+
21+
22+
def test__request_github_api__get_request(mock_https_connection):
23+
status, data = request_github_api(
24+
method="GET", url="/repos/opensource-nepal/commitlint", token="test_token"
25+
)
26+
27+
assert status == 200
28+
assert data == {"success": True}
29+
30+
mock_https_connection.return_value.request.assert_called_with(
31+
method="GET",
32+
url="/repos/opensource-nepal/commitlint",
33+
body=None,
34+
headers={
35+
"Authorization": "Bearer test_token",
36+
"Content-Type": "application/json",
37+
"User-Agent": "commitlint",
38+
},
39+
)
40+
41+
42+
def test__request_github_api__get_request_with_params(mock_https_connection):
43+
status, data = request_github_api(
44+
method="GET",
45+
url="/repos/opensource-nepal/commitlint",
46+
token="test_token",
47+
params={"key1": "val1", "key2": "val2"},
48+
)
49+
50+
assert status == 200
51+
assert data == {"success": True}
52+
53+
mock_https_connection.return_value.request.assert_called_with(
54+
method="GET",
55+
url="/repos/opensource-nepal/commitlint?key1=val1&key2=val2",
56+
body=None,
57+
headers={
58+
"Authorization": "Bearer test_token",
59+
"Content-Type": "application/json",
60+
"User-Agent": "commitlint",
61+
},
62+
)
63+
64+
65+
def test__request_github_api__post_request(mock_https_connection):
66+
status, data = request_github_api(
67+
method="POST",
68+
url="/repos/opensource-nepal/commitlint",
69+
token="test_token",
70+
)
71+
72+
assert status == 200
73+
assert data == {"success": True}
74+
75+
mock_https_connection.return_value.request.assert_called_with(
76+
method="POST",
77+
url="/repos/opensource-nepal/commitlint",
78+
body=None,
79+
headers={
80+
"Authorization": "Bearer test_token",
81+
"Content-Type": "application/json",
82+
"User-Agent": "commitlint",
83+
},
84+
)
85+
86+
87+
def test_request_github_api__post_request_with_body(mock_https_connection):
88+
status, data = request_github_api(
89+
method="POST",
90+
url="/repos/opensource-nepal/commitlint",
91+
token="test_token",
92+
body={"data": "test_data"},
93+
)
94+
95+
assert status == 200
96+
assert data == {"success": True}
97+
98+
mock_https_connection.return_value.request.assert_called_with(
99+
method="POST",
100+
url="/repos/opensource-nepal/commitlint",
101+
body=json.dumps({"data": "test_data"}),
102+
headers={
103+
"Authorization": "Bearer test_token",
104+
"Content-Type": "application/json",
105+
"User-Agent": "commitlint",
106+
},
107+
)
108+
109+
110+
def test_request_github_api__post_request_with_body_and_params(mock_https_connection):
111+
status, data = request_github_api(
112+
method="POST",
113+
url="/repos/opensource-nepal/commitlint",
114+
token="test_token",
115+
body={"data": "test_data"},
116+
params={"key1": "val1", "key2": "val2"},
117+
)
118+
119+
assert status == 200
120+
assert data == {"success": True}
121+
122+
mock_https_connection.return_value.request.assert_called_with(
123+
method="POST",
124+
url="/repos/opensource-nepal/commitlint?key1=val1&key2=val2",
125+
body=json.dumps({"data": "test_data"}),
126+
headers={
127+
"Authorization": "Bearer test_token",
128+
"Content-Type": "application/json",
129+
"User-Agent": "commitlint",
130+
},
131+
)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# type: ignore
2+
# pylint: disable=all
3+
from unittest.mock import mock_open, patch
4+
5+
from github_actions.action.utils import write_line_to_file
6+
7+
8+
@patch("builtins.open", new_callable=mock_open)
9+
def test__write_line_to_file(mock_open):
10+
write_line_to_file("dummy_path.txt", "Test line")
11+
12+
mock_open.assert_called_once_with(file="dummy_path.txt", mode="a", encoding="utf-8")
13+
mock_open().write.assert_called_once_with("Test line\n")
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# type: ignore
2+
# pylint: disable=all
3+
import os
4+
from unittest.mock import mock_open, patch
5+
6+
from github_actions.action.utils import write_output
7+
8+
9+
@patch("builtins.open", new_callable=mock_open)
10+
def test__write_output(mock_open):
11+
with patch.dict(os.environ, {"GITHUB_OUTPUT": "output.txt"}):
12+
write_output("key", "value")
13+
14+
mock_open.assert_called_once_with(file="output.txt", mode="a", encoding="utf-8")
15+
mock_open().write.assert_called_once_with("key=value\n")

‎tests/test_linter/test_utils/test_is_ingored.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
("Merge my feature", False),
2828
("Add new feature", False),
2929
("feat: this is conventional commit format", False),
30+
("Bump urllib3 from 1.26.5 to 1.26.17", True),
31+
("bump @babel/traverse from 7.22.17 to 7.24.0", True),
32+
("Bump feature1 from feature2", False),
3033
],
3134
)
3235
def test__is_ignored(commit_message, expected_result):

0 commit comments

Comments
 (0)
Please sign in to comment.