Skip to content

Commit 2dbf898

Browse files
committed
feat(github): add support for custom GitHub domains in API service
1 parent 5273dc3 commit 2dbf898

File tree

5 files changed

+82
-11
lines changed

5 files changed

+82
-11
lines changed

backend/analytics_server/mhq/exapi/github.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,20 @@ class GithubRateLimitExceeded(Exception):
2222

2323

2424
class GithubApiService:
25-
def __init__(self, access_token: str):
25+
def __init__(self, access_token: str, domain = "https://api.github.com"):
2626
self._token = access_token
27-
self._g = Github(self._token, per_page=PAGE_SIZE)
28-
self.base_url = "https://api.github.com"
27+
self.base_url = self._get_api_url(domain)
28+
self._g = Github(
29+
self._token,
30+
base_url=self.base_url,
31+
per_page=PAGE_SIZE
32+
)
2933
self.headers = {"Authorization": f"Bearer {self._token}"}
34+
def _get_api_url(self, domain: str) -> str:
35+
if domain == "https://api.github.com":
36+
return domain
37+
else:
38+
return f"{domain}/api/v3"
3039

3140
@contextlib.contextmanager
3241
def temp_config(self, per_page: int = 30):

backend/analytics_server/mhq/service/code/sync/etl_github_handler.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,26 @@ def _dt_from_github_dt_string(dt_string: str) -> datetime:
358358

359359

360360
def get_github_etl_handler(org_id: str) -> GithubETLHandler:
361+
def _get_custom_github_domain() -> Optional[str]:
362+
DEFAULT_DOMAIN = "https://api.github.com"
363+
core_repo_service = CoreRepoService()
364+
integrations = core_repo_service.get_org_integrations_for_names(
365+
org_id, [UserIdentityProvider.GITHUB.value]
366+
)
367+
368+
github_domain = (
369+
integrations[0].provider_meta.get("custom_domain")
370+
if integrations[0].provider_meta
371+
else None
372+
)
373+
374+
if not github_domain:
375+
LOG.warn(
376+
f"Custom domain not found for intergration for org {org_id} and provider {UserIdentityProvider.GITLAB.value}"
377+
)
378+
return DEFAULT_DOMAIN
379+
380+
return github_domain
361381
def _get_access_token():
362382
core_repo_service = CoreRepoService()
363383
access_token = core_repo_service.get_access_token(
@@ -371,7 +391,7 @@ def _get_access_token():
371391

372392
return GithubETLHandler(
373393
org_id,
374-
GithubApiService(_get_access_token()),
394+
GithubApiService(_get_access_token(), _get_custom_github_domain()),
375395
CodeRepoService(),
376396
CodeETLAnalyticsService(),
377397
get_revert_prs_github_sync_handler(),

backend/analytics_server/mhq/service/external_integrations_service.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,29 +26,29 @@ def __init__(
2626
self.custom_domain = custom_domain
2727

2828
def get_github_organizations(self):
29-
github_api_service = GithubApiService(self.access_token)
29+
github_api_service = GithubApiService(self.access_token, self.custom_domain)
3030
try:
3131
orgs: [GithubOrganization] = github_api_service.get_org_list()
3232
except GithubException as e:
3333
raise e
3434
return orgs
3535

3636
def get_github_org_repos(self, org_login: str, page_size: int, page: int):
37-
github_api_service = GithubApiService(self.access_token)
37+
github_api_service = GithubApiService(self.access_token, self.custom_domain)
3838
try:
3939
return github_api_service.get_repos_raw(org_login, page_size, page)
4040
except GithubException as e:
4141
raise e
4242

4343
def get_github_personal_repos(self, page_size: int, page: int):
44-
github_api_service = GithubApiService(self.access_token)
44+
github_api_service = GithubApiService(self.access_token, self.custom_domain)
4545
try:
4646
return github_api_service.get_user_repos_raw(page_size, page)
4747
except GithubException as e:
4848
raise e
4949

5050
def get_repo_workflows(self, gh_org_name: str, gh_org_repo_name: str):
51-
github_api_service = GithubApiService(self.access_token)
51+
github_api_service = GithubApiService(self.access_token, self.custom_domain)
5252
try:
5353
workflows = github_api_service.get_repo_workflows(
5454
gh_org_name, gh_org_repo_name

backend/analytics_server/mhq/service/workflows/sync/etl_github_actions_handler.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,26 @@ def _get_datetime_from_gh_datetime(datetime_str: str) -> datetime:
169169

170170

171171
def get_github_actions_etl_handler(org_id):
172+
def _get_custom_github_domain() -> Optional[str]:
173+
DEFAULT_DOMAIN = "https://api.github.com"
174+
core_repo_service = CoreRepoService()
175+
integrations = core_repo_service.get_org_integrations_for_names(
176+
org_id, [UserIdentityProvider.GITHUB.value]
177+
)
178+
179+
github_domain = (
180+
integrations[0].provider_meta.get("custom_domain")
181+
if integrations[0].provider_meta
182+
else None
183+
)
184+
185+
if not github_domain:
186+
LOG.warn(
187+
f"Custom domain not found for intergration for org {org_id} and provider {UserIdentityProvider.GITLAB.value}"
188+
)
189+
return DEFAULT_DOMAIN
190+
191+
return github_domain
172192
def _get_access_token():
173193
core_repo_service = CoreRepoService()
174194
access_token = core_repo_service.get_access_token(
@@ -181,5 +201,5 @@ def _get_access_token():
181201
return access_token
182202

183203
return GithubActionsETLHandler(
184-
org_id, GithubApiService(_get_access_token()), WorkflowRepoService()
204+
org_id, GithubApiService(_get_access_token(), _get_custom_github_domain()), WorkflowRepoService()
185205
)

web-server/pages/api/internal/[org_id]/utils.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export const searchGithubRepos = async (
5353
};
5454

5555
const searchRepoWithURL = async (searchString: string) => {
56-
const apiUrl = `https://api.github.com/repos/${searchString}`;
56+
const apiUrl = await getGitHubRestApiUrl(`repos/${searchString}`);
5757
const response = await axios.get<GithubRepo>(apiUrl);
5858
const repo = response.data;
5959
return [
@@ -104,7 +104,9 @@ export const searchGithubReposWithNames = async (
104104

105105
const queryString = `${searchString} in:name fork:true`;
106106

107-
const response = await fetch(GITHUB_API_URL, {
107+
const githubApiUrl = await getGitHubGraphQLUrl();
108+
109+
const response = await fetch(githubApiUrl, {
108110
method: 'POST',
109111
headers: {
110112
'Content-Type': 'application/json',
@@ -304,3 +306,23 @@ const replaceURL = async (url: string): Promise<string> => {
304306

305307
return url;
306308
};
309+
310+
const getGitHubCustomDomain = async (): Promise<string | null> => {
311+
const provider_meta = await db('Integration')
312+
.where('name', Integration.GITHUB)
313+
.then((r: Row<'Integration'>[]) => r.map((item) => item.provider_meta));
314+
315+
return head(provider_meta || [])?.custom_domain || null;
316+
};
317+
318+
const getGitHubRestApiUrl = async (path: string): Promise<string> => {
319+
const customDomain = await getGitHubCustomDomain();
320+
const baseUrl = customDomain ? `https://${customDomain}/api/v3` : GITHUB_API_URL;
321+
return `${baseUrl}/${path}`.replace(/\/+/g, '/');
322+
};
323+
324+
const getGitHubGraphQLUrl = async (): Promise<string> => {
325+
const customDomain = await getGitHubCustomDomain();
326+
return customDomain ? `https://${customDomain}/api/graphql` : GITHUB_API_URL;
327+
};
328+

0 commit comments

Comments
 (0)