Skip to content

Commit d4300ab

Browse files
feat: support github enterprise api
1 parent ca34478 commit d4300ab

File tree

5 files changed

+98
-33
lines changed

5 files changed

+98
-33
lines changed

auth.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,38 @@
44

55

66
def auth_to_github(
7-
gh_app_id: str,
8-
gh_app_installation_id: int,
9-
gh_app_private_key_bytes: bytes,
107
token: str,
8+
gh_app_id: int | None,
9+
gh_app_installation_id: int | None,
10+
gh_app_private_key_bytes: bytes,
1111
ghe: str,
12+
gh_app_enterprise_only: bool,
1213
) -> github3.GitHub:
1314
"""
1415
Connect to GitHub.com or GitHub Enterprise, depending on env variables.
1516
1617
Args:
17-
gh_app_id (str): the GitHub App ID
18-
gh_installation_id (int): the GitHub App Installation ID
19-
gh_app_private_key (bytes): the GitHub App Private Key
2018
token (str): the GitHub personal access token
19+
gh_app_id (int | None): the GitHub App ID
20+
gh_app_installation_id (int | None): the GitHub App Installation ID
21+
gh_app_private_key_bytes (bytes): the GitHub App Private Key
2122
ghe (str): the GitHub Enterprise URL
23+
gh_app_enterprise_only (bool): Set this to true if the GH APP is created on GHE and needs to communicate with GHE api only
2224
2325
Returns:
2426
github3.GitHub: the GitHub connection object
2527
"""
26-
2728
if gh_app_id and gh_app_private_key_bytes and gh_app_installation_id:
28-
gh = github3.github.GitHub()
29+
if ghe and gh_app_enterprise_only:
30+
gh = github3.github.GitHubEnterprise(url=ghe)
31+
else:
32+
gh = github3.github.GitHub()
2933
gh.login_as_app_installation(
3034
gh_app_private_key_bytes, gh_app_id, gh_app_installation_id
3135
)
3236
github_connection = gh
3337
elif ghe and token:
34-
github_connection = github3.github.GitHubEnterprise(ghe, token=token)
38+
github_connection = github3.github.GitHubEnterprise(url=ghe, token=token)
3539
elif token:
3640
github_connection = github3.login(token=token)
3741
else:

cleanowners.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def main(): # pragma: no cover
2727
gh_app_id,
2828
gh_app_installation_id,
2929
gh_app_private_key_bytes,
30+
gh_app_enterprise_only,
3031
token,
3132
ghe,
3233
exempt_repositories_list,
@@ -39,8 +40,14 @@ def main(): # pragma: no cover
3940

4041
# Auth to GitHub.com or GHE
4142
github_connection = auth.auth_to_github(
42-
gh_app_id, gh_app_installation_id, gh_app_private_key_bytes, token, ghe
43+
token,
44+
gh_app_id,
45+
gh_app_installation_id,
46+
gh_app_private_key_bytes,
47+
ghe,
48+
gh_app_enterprise_only,
4349
)
50+
4451
pull_count = 0
4552
eligble_for_pr_count = 0
4653
no_codeowners_count = 0
@@ -240,12 +247,12 @@ def commit_changes(
240247
commit_message,
241248
codeowners_filepath,
242249
):
243-
"""Commit the changes to the repo and open a pull reques and return the pull request object"""
250+
"""Commit the changes to the repo and open a pull request and return the pull request object"""
244251
default_branch = repo.default_branch
245252
# Get latest commit sha from default branch
246-
default_branch_commit = repo.ref("heads/" + default_branch).object.sha
253+
default_branch_commit = repo.ref(f"heads/{default_branch}").object.sha
247254
front_matter = "refs/heads/"
248-
branch_name = "codeowners-" + str(uuid.uuid4())
255+
branch_name = f"codeowners-{str(uuid.uuid4())}"
249256
repo.create_ref(front_matter + branch_name, default_branch_commit)
250257
repo.file_contents(codeowners_filepath).update(
251258
message=commit_message,

env.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def get_env_vars(
5050
int | None,
5151
int | None,
5252
bytes,
53+
bool,
5354
str | None,
5455
str,
5556
list[str],
@@ -71,6 +72,7 @@ def get_env_vars(
7172
gh_app_id (int | None): The GitHub App ID to use for authentication
7273
gh_app_installation_id (int | None): The GitHub App Installation ID to use for authentication
7374
gh_app_private_key_bytes (bytes): The GitHub App Private Key as bytes to use for authentication
75+
gh_app_enterprise_only (bool): Set this to true if the GH APP is created on GHE and needs to communicate with GHE api only
7476
token (str | None): The GitHub token to use for authentication
7577
ghe (str): The GitHub Enterprise URL to use for authentication
7678
exempt_repositories_list (list[str]): A list of repositories to exempt from the action
@@ -109,6 +111,7 @@ def get_env_vars(
109111
gh_app_id = get_int_env_var("GH_APP_ID")
110112
gh_app_private_key_bytes = os.environ.get("GH_APP_PRIVATE_KEY", "").encode("utf8")
111113
gh_app_installation_id = get_int_env_var("GH_APP_INSTALLATION_ID")
114+
gh_app_enterprise_only = get_bool_env_var("GITHUB_APP_ENTERPRISE_ONLY")
112115

113116
if gh_app_id and (not gh_app_private_key_bytes or not gh_app_installation_id):
114117
raise ValueError(
@@ -174,6 +177,7 @@ def get_env_vars(
174177
gh_app_id,
175178
gh_app_installation_id,
176179
gh_app_private_key_bytes,
180+
gh_app_enterprise_only,
177181
token,
178182
ghe,
179183
exempt_repositories_list,

test_auth.py

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,50 +4,74 @@
44
from unittest.mock import MagicMock, patch
55

66
import auth
7-
import github3.github
87

98

109
class TestAuth(unittest.TestCase):
1110
"""
1211
Test case for the auth module.
1312
"""
1413

15-
@patch("github3.github.GitHub.login_as_app_installation")
16-
def test_auth_to_github_with_github_app(self, mock_login):
17-
"""
18-
Test the auth_to_github function when GitHub app
19-
parameters provided.
20-
"""
21-
mock_login.return_value = MagicMock()
22-
result = auth.auth_to_github(12345, 678910, b"hello", "", "")
23-
24-
self.assertIsInstance(result, github3.github.GitHub)
25-
26-
def test_auth_to_github_with_token(self):
14+
@patch("github3.login")
15+
def test_auth_to_github_with_token(self, mock_login):
2716
"""
2817
Test the auth_to_github function when the token is provided.
2918
"""
30-
result = auth.auth_to_github(None, None, b"", "token", "")
19+
mock_login.return_value = "Authenticated to GitHub.com"
3120

32-
self.assertIsInstance(result, github3.github.GitHub)
21+
result = auth.auth_to_github("token", "", "", b"", "", False)
22+
23+
self.assertEqual(result, "Authenticated to GitHub.com")
3324

3425
def test_auth_to_github_without_token(self):
3526
"""
3627
Test the auth_to_github function when the token is not provided.
3728
Expect a ValueError to be raised.
3829
"""
39-
with self.assertRaises(ValueError):
40-
auth.auth_to_github(None, None, b"", "", "")
30+
with self.assertRaises(ValueError) as context_manager:
31+
auth.auth_to_github("", "", "", b"", "", False)
32+
the_exception = context_manager.exception
33+
self.assertEqual(
34+
str(the_exception),
35+
"GH_TOKEN or the set of [GH_APP_ID, GH_APP_INSTALLATION_ID, GH_APP_PRIVATE_KEY] environment variables are not set",
36+
)
4137

42-
def test_auth_to_github_with_ghe(self):
38+
@patch("github3.github.GitHubEnterprise")
39+
def test_auth_to_github_with_ghe(self, mock_ghe):
4340
"""
4441
Test the auth_to_github function when the GitHub Enterprise URL is provided.
4542
"""
43+
mock_ghe.return_value = "Authenticated to GitHub Enterprise"
44+
result = auth.auth_to_github(
45+
"token", "", "", b"", "https://github.example.com", False
46+
)
47+
48+
self.assertEqual(result, "Authenticated to GitHub Enterprise")
49+
50+
@patch("github3.github.GitHubEnterprise")
51+
def test_auth_to_github_with_ghe_and_ghe_app(self, mock_ghe):
52+
"""
53+
Test the auth_to_github function when the GitHub Enterprise URL is provided and the app was created in GitHub Enterprise URL.
54+
"""
55+
mock = mock_ghe.return_value
56+
mock.login_as_app_installation = MagicMock(return_value=True)
4657
result = auth.auth_to_github(
47-
None, None, b"", "token", "https://github.example.com"
58+
"", "123", "123", b"123", "https://github.example.com", True
4859
)
60+
mock.login_as_app_installation.assert_called_once()
61+
self.assertEqual(result, mock)
4962

50-
self.assertIsInstance(result, github3.github.GitHubEnterprise)
63+
@patch("github3.github.GitHub")
64+
def test_auth_to_github_with_app(self, mock_gh):
65+
"""
66+
Test the auth_to_github function when app credentials are provided
67+
"""
68+
mock = mock_gh.return_value
69+
mock.login_as_app_installation = MagicMock(return_value=True)
70+
result = auth.auth_to_github(
71+
"", "123", "123", b"123", "https://github.example.com", False
72+
)
73+
mock.login_as_app_installation.assert_called_once()
74+
self.assertEqual(result, mock)
5175

5276

5377
if __name__ == "__main__":

test_env.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def test_get_env_vars_with_org(self):
6161
None,
6262
None,
6363
b"",
64+
False,
6465
TOKEN,
6566
"",
6667
["repo4", "repo5"],
@@ -99,6 +100,7 @@ def test_get_env_vars_with_github_app_and_repos(self):
99100
12345,
100101
678910,
101102
b"hello",
103+
False,
102104
"",
103105
"",
104106
["repo4", "repo5"],
@@ -111,6 +113,27 @@ def test_get_env_vars_with_github_app_and_repos(self):
111113
result = get_env_vars(True)
112114
self.assertEqual(result, expected_result)
113115

116+
@patch.dict(
117+
os.environ,
118+
{
119+
"ORGANIZATION": "my_organization",
120+
"GH_APP_ID": "12345",
121+
"GH_APP_INSTALLATION_ID": "",
122+
"GH_APP_PRIVATE_KEY": "",
123+
"GH_TOKEN": "",
124+
},
125+
clear=True,
126+
)
127+
def test_get_env_vars_auth_with_github_app_installation_missing_inputs(self):
128+
"""Test that an error is raised there are missing inputs for the gh app"""
129+
with self.assertRaises(ValueError) as context_manager:
130+
get_env_vars(True)
131+
the_exception = context_manager.exception
132+
self.assertEqual(
133+
str(the_exception),
134+
"GH_APP_ID set and GH_APP_INSTALLATION_ID or GH_APP_PRIVATE_KEY variable not set",
135+
)
136+
114137
@patch.dict(
115138
os.environ,
116139
{
@@ -137,6 +160,7 @@ def test_get_env_vars_with_token_and_repos(self):
137160
None,
138161
None,
139162
b"",
163+
False,
140164
TOKEN,
141165
"",
142166
["repo4", "repo5"],
@@ -171,6 +195,7 @@ def test_get_env_vars_optional_values(self):
171195
None,
172196
None,
173197
b"",
198+
False,
174199
TOKEN,
175200
"",
176201
[],
@@ -220,6 +245,7 @@ def test_get_env_vars_with_repos_no_dry_run(self):
220245
None,
221246
None,
222247
b"",
248+
False,
223249
TOKEN,
224250
"",
225251
[],

0 commit comments

Comments
 (0)