16
16
# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
17
"""Wrapper for the GitLab API."""
18
18
19
+ import abc
19
20
import os
21
+ import sys
20
22
import time
21
23
from typing import Any , cast , Dict , List , Optional , Tuple , TYPE_CHECKING , Union
22
24
30
32
import gitlab .exceptions
31
33
from gitlab import utils
32
34
35
+ if TYPE_CHECKING or ("sphinx" in sys .modules ):
36
+ import gql
37
+ from graphql import DocumentNode
38
+
33
39
REDIRECT_MSG = (
34
40
"python-gitlab detected a {status_code} ({reason!r}) redirection. You must update "
35
41
"your GitLab URL to the correct URL to avoid issues. The redirection was from: "
45
51
)
46
52
47
53
48
- class Gitlab :
54
+ class _BaseGitlab :
49
55
"""Represents a GitLab server connection.
50
56
51
57
Args:
@@ -76,21 +82,14 @@ def __init__(
76
82
ssl_verify : Union [bool , str ] = True ,
77
83
http_username : Optional [str ] = None ,
78
84
http_password : Optional [str ] = None ,
79
- timeout : Optional [float ] = None ,
80
- api_version : str = "4" ,
81
85
session : Optional [requests .Session ] = None ,
82
- per_page : Optional [int ] = None ,
83
- pagination : Optional [str ] = None ,
84
- order_by : Optional [str ] = None ,
86
+ timeout : Optional [float ] = None ,
85
87
user_agent : str = gitlab .const .USER_AGENT ,
86
88
retry_transient_errors : bool = False ,
87
89
) -> None :
88
-
89
- self ._api_version = str (api_version )
90
90
self ._server_version : Optional [str ] = None
91
91
self ._server_revision : Optional [str ] = None
92
92
self ._base_url = self ._get_base_url (url )
93
- self ._url = f"{ self ._base_url } /api/v{ api_version } "
94
93
#: Timeout to use for requests to gitlab server
95
94
self .timeout = timeout
96
95
self .retry_transient_errors = retry_transient_errors
@@ -110,6 +109,84 @@ def __init__(
110
109
#: Create a session object for requests
111
110
self .session = session or requests .Session ()
112
111
112
+ def _get_base_url (self , url : Optional [str ] = None ) -> str :
113
+ """Return the base URL with the trailing slash stripped.
114
+ If the URL is a Falsy value, return the default URL.
115
+ Returns:
116
+ The base URL
117
+ """
118
+ if not url :
119
+ return gitlab .const .DEFAULT_URL
120
+
121
+ return url .rstrip ("/" )
122
+
123
+ @property
124
+ def url (self ) -> str :
125
+ """The user-provided server URL."""
126
+ return self ._base_url
127
+
128
+ @abc .abstractmethod
129
+ def _set_auth_info (self ) -> None :
130
+ pass
131
+
132
+
133
+ class Gitlab (_BaseGitlab ):
134
+ """Represents a GitLab server connection.
135
+
136
+ Args:
137
+ url: The URL of the GitLab server (defaults to https://gitlab.com).
138
+ private_token: The user private token
139
+ oauth_token: An oauth token
140
+ job_token: A CI job token
141
+ ssl_verify: Whether SSL certificates should be validated. If
142
+ the value is a string, it is the path to a CA file used for
143
+ certificate validation.
144
+ timeout: Timeout to use for requests to the GitLab server.
145
+ http_username: Username for HTTP authentication
146
+ http_password: Password for HTTP authentication
147
+ api_version: Gitlab API version to use (support for 4 only)
148
+ pagination: Can be set to 'keyset' to use keyset pagination
149
+ order_by: Set order_by globally
150
+ user_agent: A custom user agent to use for making HTTP requests.
151
+ retry_transient_errors: Whether to retry after 500, 502, 503, 504
152
+ or 52x responses. Defaults to False.
153
+ """
154
+
155
+ def __init__ (
156
+ self ,
157
+ url : Optional [str ] = None ,
158
+ private_token : Optional [str ] = None ,
159
+ oauth_token : Optional [str ] = None ,
160
+ job_token : Optional [str ] = None ,
161
+ ssl_verify : Union [bool , str ] = True ,
162
+ http_username : Optional [str ] = None ,
163
+ http_password : Optional [str ] = None ,
164
+ timeout : Optional [float ] = None ,
165
+ api_version : str = "4" ,
166
+ session : Optional [requests .Session ] = None ,
167
+ per_page : Optional [int ] = None ,
168
+ pagination : Optional [str ] = None ,
169
+ order_by : Optional [str ] = None ,
170
+ user_agent : str = gitlab .const .USER_AGENT ,
171
+ retry_transient_errors : bool = False ,
172
+ ) -> None :
173
+ super ().__init__ (
174
+ url ,
175
+ private_token ,
176
+ oauth_token ,
177
+ job_token ,
178
+ ssl_verify ,
179
+ http_username ,
180
+ http_password ,
181
+ session ,
182
+ timeout ,
183
+ user_agent ,
184
+ retry_transient_errors ,
185
+ )
186
+ self ._api_version = str (api_version )
187
+ self ._url = f"{ self ._base_url } /api/v{ api_version } "
188
+ self ._set_auth_info ()
189
+
113
190
self .per_page = per_page
114
191
self .pagination = pagination
115
192
self .order_by = order_by
@@ -215,11 +292,6 @@ def __setstate__(self, state: Dict[str, Any]) -> None:
215
292
216
293
self ._objects = gitlab .v4 .objects
217
294
218
- @property
219
- def url (self ) -> str :
220
- """The user-provided server URL."""
221
- return self ._base_url
222
-
223
295
@property
224
296
def api_url (self ) -> str :
225
297
"""The computed API base URL."""
@@ -531,17 +603,6 @@ def _get_session_opts(self) -> Dict[str, Any]:
531
603
"verify" : self .ssl_verify ,
532
604
}
533
605
534
- def _get_base_url (self , url : Optional [str ] = None ) -> str :
535
- """Return the base URL with the trailing slash stripped.
536
- If the URL is a Falsy value, return the default URL.
537
- Returns:
538
- The base URL
539
- """
540
- if not url :
541
- return gitlab .const .DEFAULT_URL
542
-
543
- return url .rstrip ("/" )
544
-
545
606
def _build_url (self , path : str ) -> str :
546
607
"""Returns the full url from path.
547
608
@@ -1150,3 +1211,66 @@ def next(self) -> Dict[str, Any]:
1150
1211
return self .next ()
1151
1212
1152
1213
raise StopIteration
1214
+
1215
+
1216
+ class GraphQLGitlab (_BaseGitlab ):
1217
+ def __init__ (
1218
+ self ,
1219
+ url : Optional [str ] = None ,
1220
+ private_token : Optional [str ] = None ,
1221
+ oauth_token : Optional [str ] = None ,
1222
+ job_token : Optional [str ] = None ,
1223
+ ssl_verify : Union [bool , str ] = True ,
1224
+ http_username : Optional [str ] = None ,
1225
+ http_password : Optional [str ] = None ,
1226
+ session : Optional [requests .Session ] = None ,
1227
+ timeout : Optional [float ] = None ,
1228
+ user_agent : str = gitlab .const .USER_AGENT ,
1229
+ retry_transient_errors : bool = False ,
1230
+ fetch_schema_from_transport : bool = False ,
1231
+ ) -> None :
1232
+ super ().__init__ (
1233
+ url ,
1234
+ private_token ,
1235
+ oauth_token ,
1236
+ job_token ,
1237
+ ssl_verify ,
1238
+ http_username ,
1239
+ http_password ,
1240
+ session ,
1241
+ timeout ,
1242
+ user_agent ,
1243
+ retry_transient_errors ,
1244
+ )
1245
+ self ._url = f"{ self ._base_url } /api/graphql"
1246
+ self .fetch_schema_from_transport = fetch_schema_from_transport
1247
+
1248
+ try :
1249
+ import gql
1250
+ from gql .dsl import DSLSchema
1251
+
1252
+ from .graphql .transport import GitlabSyncTransport
1253
+ except ImportError :
1254
+ raise ImportError (
1255
+ "The GraphQLGitlab client could not be initialized because "
1256
+ "the gql dependency is not installed. "
1257
+ "Install it with 'pip install python-gitlab[graphql]'"
1258
+ )
1259
+
1260
+ self ._transport = GitlabSyncTransport (self ._url , session = self .session )
1261
+ self ._client = gql .Client (
1262
+ transport = self ._transport ,
1263
+ fetch_schema_from_transport = fetch_schema_from_transport ,
1264
+ )
1265
+
1266
+ def _set_auth_info (self ) -> None :
1267
+ if self .private_token and self .oauth_token :
1268
+ raise ValueError (
1269
+ "Only one of private_token or oauth_token should be defined"
1270
+ )
1271
+
1272
+ token = self .private_token or self .oauth_token
1273
+ self .headers ["Authorization" ] = f"Bearer { token } "
1274
+
1275
+ def execute (self , document : "DocumentNode" , * args , ** kwargs ) -> Any :
1276
+ return self ._client .execute (document , * args , ** kwargs )
0 commit comments