Skip to content

Commit

Permalink
Derive GraphQL URL from base_url (#2880)
Browse files Browse the repository at this point in the history
  • Loading branch information
EnricoMi committed Jan 25, 2024
1 parent e47c153 commit d0caa3c
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 3 deletions.
29 changes: 26 additions & 3 deletions github/Requester.py
Expand Up @@ -52,6 +52,7 @@
# Copyright 2023 Phillip Tran <phillip.qtr@gmail.com> #
# Copyright 2023 Trim21 <trim21.me@gmail.com> #
# Copyright 2023 adosibalo <94008816+adosibalo@users.noreply.github.com> #
# Copyright 2024 Enrico Minack <github@enrico.minack.dev> #
# #
# This file is part of PyGithub. #
# http://pygithub.readthedocs.io/ #
Expand Down Expand Up @@ -395,6 +396,8 @@ def __init__(
self.__base_url = base_url

o = urllib.parse.urlparse(base_url)
self.__graphql_prefix = self.get_graphql_prefix(o.path)
self.__graphql_url = urllib.parse.urlunparse(o._replace(path=self.__graphql_prefix))
self.__hostname = o.hostname # type: ignore
self.__port = o.port
self.__prefix = o.path
Expand Down Expand Up @@ -450,6 +453,22 @@ def __setstate__(self, state: Dict[str, Any]) -> None:
self.__connection = None
self.__custom_connections = deque()

@staticmethod
# replace with str.removesuffix once support for Python 3.7 is dropped
def remove_suffix(string: str, suffix: str) -> str:
if string.endswith(suffix):
return string[: -len(suffix)]
return string

@staticmethod
def get_graphql_prefix(path: Optional[str]) -> str:
if path is None or path in ["", "/"]:
path = ""
if path.endswith(("/v3", "/v3/")):
path = Requester.remove_suffix(path, "/")
path = Requester.remove_suffix(path, "/v3")
return path + "/graphql"

def close(self) -> None:
"""
Close the connection to the server.
Expand Down Expand Up @@ -485,6 +504,10 @@ def kwargs(self) -> Dict[str, Any]:
def base_url(self) -> str:
return self.__base_url

@property
def graphql_url(self) -> str:
return self.__graphql_url

@property
def hostname(self) -> str:
return self.__hostname
Expand Down Expand Up @@ -540,7 +563,7 @@ def graphql_query(self, query: str, variables: Dict[str, Any]) -> Tuple[Dict[str
"""
input_ = {"query": query, "variables": {"input": variables}}

response_headers, data = self.requestJsonAndCheck("POST", "https://api.github.com/graphql", input=input_)
response_headers, data = self.requestJsonAndCheck("POST", self.graphql_url, input=input_)
if "errors" in data:
raise self.createException(400, response_headers, data)
return response_headers, data
Expand Down Expand Up @@ -894,8 +917,8 @@ def __makeAbsoluteUrl(self, url: str) -> str:
"status.github.com",
"github.com",
], o.hostname
assert o.path.startswith((self.__prefix, "/api/"))
assert o.port == self.__port
assert o.path.startswith((self.__prefix, self.__graphql_prefix, "/api/")), o.path
assert o.port == self.__port, o.port
url = o.path
if o.query != "":
url += f"?{o.query}"
Expand Down
76 changes: 76 additions & 0 deletions tests/GraphQl.py
@@ -0,0 +1,76 @@
############################ Copyrights and license ############################
# #
# Copyright 2024 Enrico Minack <github@enrico.minack.dev> #
# #
# This file is part of PyGithub. #
# http://pygithub.readthedocs.io/ #
# #
# PyGithub is free software: you can redistribute it and/or modify it under #
# the terms of the GNU Lesser General Public License as published by the Free #
# Software Foundation, either version 3 of the License, or (at your option) #
# any later version. #
# #
# PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY #
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more #
# details. #
# #
# You should have received a copy of the GNU Lesser General Public License #
# along with PyGithub. If not, see <http://www.gnu.org/licenses/>. #
# #
################################################################################

from typing import Any, Dict

import github
from github import Github

from . import Framework


class GraphQl(Framework.TestCase):
def setUp(self):
super().setUp()

def expected(self, base_url: str = "https://github.com") -> Dict[Any, Any]:
return {
"data": {
"disablePullRequestAutoMerge": {
"actor": {
"avatarUrl": "https://avatars.githubusercontent.com/u/14806300?u=786f9f8ef8782d45381b01580f7f7783cf9c7e37&v=4",
"login": "heitorpolidoro",
"resourcePath": "/heitorpolidoro",
"url": f"{base_url}/heitorpolidoro",
},
"clientMutationId": None,
}
}
}

def testRequesterGraphQlPrefix(self):
get_graphql_prefix = github.Requester.Requester.get_graphql_prefix
assert "/graphql" == get_graphql_prefix(None)
assert "/graphql" == get_graphql_prefix("")
assert "/graphql" == get_graphql_prefix("/")
assert "/api/graphql" == get_graphql_prefix("/api/v3")
assert "/path/to/github/api/graphql" == get_graphql_prefix("/path/to/github/api/v3")
assert "/path/to/github/graphql" == get_graphql_prefix("/path/to/github")

def testDefaultUrl(self):
pull = self.g.get_repo("PyGithub/PyGithub").get_pull(31)
response = pull.disable_automerge()
assert response == self.expected()

def testOtherUrl(self):
base_url = "https://my.enterprise.com/api/v3"
gh = Github(base_url=base_url)
pull = gh.get_repo("PyGithub/PyGithub").get_pull(31)
response = pull.disable_automerge()
assert response == self.expected(base_url)

def testOtherPort(self):
base_url = "https://my.enterprise.com:8080/api/v3"
gh = Github(base_url=base_url)
pull = gh.get_repo("PyGithub/PyGithub").get_pull(31)
response = pull.disable_automerge()
assert response == self.expected(base_url)

0 comments on commit d0caa3c

Please sign in to comment.