clear-skies-gitlab 2.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- clear_skies_gitlab-2.0.1.dist-info/METADATA +75 -0
- clear_skies_gitlab-2.0.1.dist-info/RECORD +42 -0
- clear_skies_gitlab-2.0.1.dist-info/WHEEL +4 -0
- clear_skies_gitlab-2.0.1.dist-info/licenses/LICENSE +21 -0
- clearskies_gitlab/__init__.py +3 -0
- clearskies_gitlab/backends/__init__.py +9 -0
- clearskies_gitlab/backends/gitlab_rest_backend.py +150 -0
- clearskies_gitlab/defaults/__init__.py +7 -0
- clearskies_gitlab/defaults/gitlab_default_auth.py +7 -0
- clearskies_gitlab/defaults/gitlab_default_url.py +7 -0
- clearskies_gitlab/exceptions/__init__.py +13 -0
- clearskies_gitlab/exceptions/gitlab_error.py +50 -0
- clearskies_gitlab/models/__init__.py +19 -0
- clearskies_gitlab/models/gitlab_cicd_variable.py +23 -0
- clearskies_gitlab/models/gitlab_gql_model.py +9 -0
- clearskies_gitlab/models/gitlab_group.py +69 -0
- clearskies_gitlab/models/gitlab_member.py +24 -0
- clearskies_gitlab/models/gitlab_namespace.py +32 -0
- clearskies_gitlab/models/gitlab_project.py +110 -0
- clearskies_gitlab/models/gitlab_rest_model.py +11 -0
- clearskies_gitlab/models/rest/__init__.py +35 -0
- clearskies_gitlab/models/rest/gitlab_rest_advanced_search.py +38 -0
- clearskies_gitlab/models/rest/gitlab_rest_advanced_search_blob.py +26 -0
- clearskies_gitlab/models/rest/gitlab_rest_current_user.py +43 -0
- clearskies_gitlab/models/rest/gitlab_rest_group.py +75 -0
- clearskies_gitlab/models/rest/gitlab_rest_group_access_token.py +32 -0
- clearskies_gitlab/models/rest/gitlab_rest_group_member.py +28 -0
- clearskies_gitlab/models/rest/gitlab_rest_group_member_reference.py +6 -0
- clearskies_gitlab/models/rest/gitlab_rest_group_project.py +37 -0
- clearskies_gitlab/models/rest/gitlab_rest_group_reference.py +6 -0
- clearskies_gitlab/models/rest/gitlab_rest_group_search.py +21 -0
- clearskies_gitlab/models/rest/gitlab_rest_group_search_blob.py +13 -0
- clearskies_gitlab/models/rest/gitlab_rest_group_subgroup.py +65 -0
- clearskies_gitlab/models/rest/gitlab_rest_group_subgroup_reference.py +6 -0
- clearskies_gitlab/models/rest/gitlab_rest_group_variable.py +22 -0
- clearskies_gitlab/models/rest/gitlab_rest_namespace.py +69 -0
- clearskies_gitlab/models/rest/gitlab_rest_project.py +81 -0
- clearskies_gitlab/models/rest/gitlab_rest_project_reference.py +6 -0
- clearskies_gitlab/models/rest/gitlab_rest_project_repository_commit.py +44 -0
- clearskies_gitlab/models/rest/gitlab_rest_project_repository_commit_diff.py +34 -0
- clearskies_gitlab/models/rest/gitlab_rest_project_variable.py +24 -0
- clearskies_gitlab/models/rest/gitlab_rest_project_variable_refence.py +6 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: clear-skies-gitlab
|
|
3
|
+
Version: 2.0.1
|
|
4
|
+
Summary: Gitlab module for Clearskies
|
|
5
|
+
Project-URL: Docs, https://https://clearskies.info/modules/clear-skies-gitlab
|
|
6
|
+
Project-URL: Repository, https://github.com/clearskies-py/gitlab
|
|
7
|
+
Project-URL: Issues, https://github.com/clearskies-py/gitlab/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/clearskies-py/gitlab/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Tom Nijboer <tom.nijboer@cimpress.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Requires-Python: <4.0,>=3.11
|
|
17
|
+
Requires-Dist: clear-skies>=2.0.0
|
|
18
|
+
Requires-Dist: gql>=4.0.0
|
|
19
|
+
Requires-Dist: requests>=2.32.5
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: types-requests>=2.32.4; extra == 'dev'
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# gitlab
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
Gitlab module for Clearskies
|
|
29
|
+
|
|
30
|
+
This template scaffolds a dynamic Clearskies module for any kind of logic, integration, or API. You can use it to build modules for data processing, service integration, automation, or any custom business logic.
|
|
31
|
+
|
|
32
|
+
Your module can implement any logic you need: fetch data, process input, interact with external services, or perform custom actions. The endpoints and payloads are up to you.
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Install uv if not already installed
|
|
38
|
+
pip install uv
|
|
39
|
+
|
|
40
|
+
# Create a virtual environment and install dependencies
|
|
41
|
+
uv sync
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Development
|
|
45
|
+
|
|
46
|
+
To set up your development environment with pre-commit hooks:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Install uv if not already installed
|
|
50
|
+
pip install uv
|
|
51
|
+
|
|
52
|
+
# Create a virtual environment and install all dependencies (including dev)
|
|
53
|
+
uv sync
|
|
54
|
+
|
|
55
|
+
# Install dev dependencies (including ruff, black, mypy) in the project environment
|
|
56
|
+
uv pip install .[dev]
|
|
57
|
+
|
|
58
|
+
# Install pre-commit hooks
|
|
59
|
+
uv run pre-commit install
|
|
60
|
+
|
|
61
|
+
# Optionally, run pre-commit on all files
|
|
62
|
+
uv run pre-commit run --all-files
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Usage Example
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
import clearskies
|
|
69
|
+
import clearskies_gitlab
|
|
70
|
+
|
|
71
|
+
wsgi = clearskies.contexts.WsgiRef(
|
|
72
|
+
clearskies_gitlab.build__module()
|
|
73
|
+
)
|
|
74
|
+
wsgi()
|
|
75
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
clearskies_gitlab/__init__.py,sha256=ClIA0vw3F7SEkiHWukom62Vc023czAhujTj61w8nZL0,129
|
|
2
|
+
clearskies_gitlab/backends/__init__.py,sha256=edqByrjBImEUO1KvHjBHpA9X15uRXxstCYo9UXpJkPM,254
|
|
3
|
+
clearskies_gitlab/backends/gitlab_rest_backend.py,sha256=v8HiKbQyn5i0OvOr6w8Zag4BQznIrDQNg2FaLgL1Iaw,6543
|
|
4
|
+
clearskies_gitlab/defaults/__init__.py,sha256=GF1ggkRAFoRP7F0mzUj0lfMV1WneKa8z3f5eDWLhCKY,216
|
|
5
|
+
clearskies_gitlab/defaults/gitlab_default_auth.py,sha256=iwlvQrYkODVwoyj4hkRdq-OHaLXX0kxasPvBuyTIHnY,323
|
|
6
|
+
clearskies_gitlab/defaults/gitlab_default_url.py,sha256=lfjr5_rNydY-yGGzKp1D-ANdbc51_yIz2AEUF07tO9U,288
|
|
7
|
+
clearskies_gitlab/exceptions/__init__.py,sha256=QUg8lVn91QMENpN_uZmYdNkhI1EjFAWN9X6cMKgKmtE,301
|
|
8
|
+
clearskies_gitlab/exceptions/gitlab_error.py,sha256=DUplWahAT2hC6GZiuapVZc_PEb-D3068CJmaGFg_yek,2000
|
|
9
|
+
clearskies_gitlab/models/__init__.py,sha256=jJ0Knev4oE8ew_RI01rDD-0G1WOZdF7wfyuaGFb9wUk,645
|
|
10
|
+
clearskies_gitlab/models/gitlab_cicd_variable.py,sha256=Bzk6M6ycIqeUxY6uhT_3zRBxm7pkOqdPjEk4JYO2oxM,506
|
|
11
|
+
clearskies_gitlab/models/gitlab_gql_model.py,sha256=NkmQEqECofkNTDWjSywniUCYDG2inejzVgLxyBfqecg,189
|
|
12
|
+
clearskies_gitlab/models/gitlab_group.py,sha256=mmruk1OLSLb5cwN8xtOY30tCXbgtngz399N4WFzzNa4,2283
|
|
13
|
+
clearskies_gitlab/models/gitlab_member.py,sha256=-x0xU_Kf14Bkc9-h27KYxSbdmS6X2LthLI2Gdch0C80,547
|
|
14
|
+
clearskies_gitlab/models/gitlab_namespace.py,sha256=fW9ADAqXrWPJoVBrQo0JbJvccJZKaGmXtJjShwgXxII,917
|
|
15
|
+
clearskies_gitlab/models/gitlab_project.py,sha256=Fx9xiUrhO4YWdCRSFQLuFphPVZEGNfUoj1Cwo2VdJ-0,4223
|
|
16
|
+
clearskies_gitlab/models/gitlab_rest_model.py,sha256=XnlKBuORJPi4AKPNSuCasx3blmmpWZZv-nJfzYbQ54E,225
|
|
17
|
+
clearskies_gitlab/models/rest/__init__.py,sha256=auEn31pkPk8zcbw6ZamNrMbltydjufUIxh-WhcpWx6w,1854
|
|
18
|
+
clearskies_gitlab/models/rest/gitlab_rest_advanced_search.py,sha256=9ftD-rcMhEejzQdEQBxNpQOxtL0yywB0mg5peSpCyMk,893
|
|
19
|
+
clearskies_gitlab/models/rest/gitlab_rest_advanced_search_blob.py,sha256=ZDko71JUsL1-dIsoWulQVlY30L6GMHS8taFUL_k9fn0,688
|
|
20
|
+
clearskies_gitlab/models/rest/gitlab_rest_current_user.py,sha256=fCyrkk3KO66nTH2I7ioggqdUHRSDOKofZRB9qlD19_4,1107
|
|
21
|
+
clearskies_gitlab/models/rest/gitlab_rest_group.py,sha256=wFXleyn34d1gz9pVBYubuBNLx5B2vkcFv9pEtc83DXM,2102
|
|
22
|
+
clearskies_gitlab/models/rest/gitlab_rest_group_access_token.py,sha256=Wx2NOzsgaRizKZNNk_BqAmUq3wOU8E0YQCdzxE8IzR0,904
|
|
23
|
+
clearskies_gitlab/models/rest/gitlab_rest_group_member.py,sha256=0L03cVruwUvJa-laJVA1bVULJM_gS2DZJGjkgF08Sbc,774
|
|
24
|
+
clearskies_gitlab/models/rest/gitlab_rest_group_member_reference.py,sha256=y1gbRc-XJljMizOOa2diA-cxAllACykN7h08RNzfn6k,200
|
|
25
|
+
clearskies_gitlab/models/rest/gitlab_rest_group_project.py,sha256=bQXIFz1GiLjIB2Pm6W_4JuqEd0sefumpmEFMo8_L0Z8,865
|
|
26
|
+
clearskies_gitlab/models/rest/gitlab_rest_group_reference.py,sha256=mJTBjjiPfjYgngzcotUjcWPPRBA0wdUCcOZKdIrxVcQ,174
|
|
27
|
+
clearskies_gitlab/models/rest/gitlab_rest_group_search.py,sha256=Q_bR6es8l8vZGi5u_31d9V2QY6byzYZAu_ACNEWJx7k,547
|
|
28
|
+
clearskies_gitlab/models/rest/gitlab_rest_group_search_blob.py,sha256=EhCs3KkaZsdmf85Ctt8Wgq681YvmgeYK47VBh1bdRIE,353
|
|
29
|
+
clearskies_gitlab/models/rest/gitlab_rest_group_subgroup.py,sha256=l9bGhkULbL0wtQxp4XfoQS7vwfcJdY96NxsKq4FHvKE,1781
|
|
30
|
+
clearskies_gitlab/models/rest/gitlab_rest_group_subgroup_reference.py,sha256=CXdGQQ4Aswk5e4ixMTn8wWGotI5ETl-xESRPuueJSIA,208
|
|
31
|
+
clearskies_gitlab/models/rest/gitlab_rest_group_variable.py,sha256=s24Q6agioITIfX9G2xnNAzySR0BflGiYnLgrXfCGeFQ,629
|
|
32
|
+
clearskies_gitlab/models/rest/gitlab_rest_namespace.py,sha256=PmY2yHY63G2DJBOo5Xe6BdzfcGumM4cVlX1aONLesEY,1919
|
|
33
|
+
clearskies_gitlab/models/rest/gitlab_rest_project.py,sha256=diO2-8QiN9VvXCNa7egKTnIp6SFl6P2lHrG5wkjaUbk,2492
|
|
34
|
+
clearskies_gitlab/models/rest/gitlab_rest_project_reference.py,sha256=oK42SyFQQTIFeidstoIz-_PFq9qwlzyvhq9cmJcqg2E,182
|
|
35
|
+
clearskies_gitlab/models/rest/gitlab_rest_project_repository_commit.py,sha256=R3Km247_TDyYqtQEGM1w5r1BYpUtA1j0cS2XA06Q9tw,1171
|
|
36
|
+
clearskies_gitlab/models/rest/gitlab_rest_project_repository_commit_diff.py,sha256=EAZd1H6AnuwvzW4ZH5KX4prNn_RoV_0PzBlPOHkXOiQ,892
|
|
37
|
+
clearskies_gitlab/models/rest/gitlab_rest_project_variable.py,sha256=FylNaIBiFx7oVOIz9Nltdp0GT2OsjSghDD4nLQAQ1pA,790
|
|
38
|
+
clearskies_gitlab/models/rest/gitlab_rest_project_variable_refence.py,sha256=jdiE-9v5yovfk5HM7vkmQlkkAthmI6YNh6sDQrrjoSU,216
|
|
39
|
+
clear_skies_gitlab-2.0.1.dist-info/METADATA,sha256=aMsKuagx7ecWaqdlzEeTmFT3z4PRzJ99OONnPPxBUAw,2138
|
|
40
|
+
clear_skies_gitlab-2.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
41
|
+
clear_skies_gitlab-2.0.1.dist-info/licenses/LICENSE,sha256=MkEX8JF8kZxdyBpTTcB0YTd-xZpWnHvbRlw-pQh8u58,1069
|
|
42
|
+
clear_skies_gitlab-2.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, Tom Nijboer
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import urllib
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
7
|
+
|
|
8
|
+
import requests
|
|
9
|
+
from clearskies import Column, Model, configs
|
|
10
|
+
from clearskies.backends import ApiBackend
|
|
11
|
+
from clearskies.decorators import parameters_to_properties
|
|
12
|
+
from clearskies.di import inject
|
|
13
|
+
from clearskies.functional import string
|
|
14
|
+
from clearskies.query import Query
|
|
15
|
+
from requests.structures import CaseInsensitiveDict
|
|
16
|
+
|
|
17
|
+
from clearskies_gitlab.exceptions import gitlab_error
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from clearskies import model
|
|
21
|
+
from clearskies.authentication import Authentication
|
|
22
|
+
from clearskies.query import Query
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class GitlabRestBackend(ApiBackend):
|
|
26
|
+
"""Backend for Gitlab.com."""
|
|
27
|
+
|
|
28
|
+
base_url = inject.ByName("gitlab_url", cache=True)
|
|
29
|
+
authentication = inject.ByName("gitlab_auth", cache=False)
|
|
30
|
+
requests = inject.Requests()
|
|
31
|
+
_auth_headers: dict[str, str] = {}
|
|
32
|
+
|
|
33
|
+
api_to_model_map = configs.AnyDict(default={})
|
|
34
|
+
pagination_parameter_name = configs.String(default="page")
|
|
35
|
+
|
|
36
|
+
@parameters_to_properties
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
base_url: str | None = None,
|
|
40
|
+
authentication: Authentication | None = None,
|
|
41
|
+
model_casing: str = "snake_case",
|
|
42
|
+
api_casing: str = "snake_case",
|
|
43
|
+
api_to_model_map: dict[str, str | list[str]] = {},
|
|
44
|
+
pagination_parameter_name: str = "page",
|
|
45
|
+
pagination_parameter_type: str = "str",
|
|
46
|
+
limit_parameter_name: str = "per_page",
|
|
47
|
+
):
|
|
48
|
+
self.finalize_and_validate_configuration()
|
|
49
|
+
|
|
50
|
+
def count_method(self, query: Query) -> str:
|
|
51
|
+
"""Return the request method to use when making a request for a record count."""
|
|
52
|
+
return "HEAD"
|
|
53
|
+
|
|
54
|
+
def count(self, query: Query) -> int:
|
|
55
|
+
"""Return the count of records matching the query."""
|
|
56
|
+
self.check_query(query)
|
|
57
|
+
(url, method, body, headers) = self.build_records_request(query)
|
|
58
|
+
response = self.execute_request(url, self.count_method(query), json=body, headers=headers)
|
|
59
|
+
return self._map_count_response(response.headers)
|
|
60
|
+
|
|
61
|
+
def _map_count_response(self, headers: CaseInsensitiveDict[str]) -> int:
|
|
62
|
+
return int(headers.get("x-total", 0))
|
|
63
|
+
|
|
64
|
+
# def map_records_response(
|
|
65
|
+
# self, response_data: Any, query: Query, query_data: dict[str, Any] | None = None
|
|
66
|
+
# ) -> list[dict[str, Any]]:
|
|
67
|
+
# """Map the response data to model records with support for nested fields."""
|
|
68
|
+
# if query_data is None:
|
|
69
|
+
# query_data = {}
|
|
70
|
+
|
|
71
|
+
# columns = query.model_class.get_columns()
|
|
72
|
+
# result = []
|
|
73
|
+
|
|
74
|
+
# # Handle list response
|
|
75
|
+
# if isinstance(response_data, list):
|
|
76
|
+
# for item in response_data:
|
|
77
|
+
# if not isinstance(item, dict):
|
|
78
|
+
# continue
|
|
79
|
+
# mapped = self.check_dict_and_map_to_model(item, columns, query_data)
|
|
80
|
+
# if mapped:
|
|
81
|
+
# result.append(mapped)
|
|
82
|
+
# # Handle single object response
|
|
83
|
+
# elif isinstance(response_data, dict):
|
|
84
|
+
# mapped = self.check_dict_and_map_to_model(response_data, columns, query_data)
|
|
85
|
+
# if mapped:
|
|
86
|
+
# result.append(mapped)
|
|
87
|
+
|
|
88
|
+
# return result
|
|
89
|
+
|
|
90
|
+
def conditions_to_request_parameters(
|
|
91
|
+
self, query: Query, used_routing_parameters: list[str]
|
|
92
|
+
) -> tuple[str, dict[str, str], dict[str, Any]]:
|
|
93
|
+
route_id = ""
|
|
94
|
+
|
|
95
|
+
url_parameters = {}
|
|
96
|
+
for condition in query.conditions:
|
|
97
|
+
if condition.column_name in used_routing_parameters:
|
|
98
|
+
continue
|
|
99
|
+
if condition.operator != "=":
|
|
100
|
+
raise ValueError(
|
|
101
|
+
f"I'm not very smart and only know how to search with the equals operator, but I received a condition of {condition.parsed}. If you need to support this, you'll have to extend the ApiBackend and overwrite the build_records_request method."
|
|
102
|
+
)
|
|
103
|
+
if condition.column_name == query.model_class.id_column_name:
|
|
104
|
+
route_id = urllib.parse.quote_plus(condition.values[0]).replace("+", "%20")
|
|
105
|
+
continue
|
|
106
|
+
url_parameters[condition.column_name] = condition.values[0]
|
|
107
|
+
|
|
108
|
+
return (route_id, url_parameters, {})
|
|
109
|
+
|
|
110
|
+
# def set_next_page_data_from_response(
|
|
111
|
+
# self,
|
|
112
|
+
# next_page_data: dict[str, Any],
|
|
113
|
+
# query: Query,
|
|
114
|
+
# response: requests.Response, # type: ignore
|
|
115
|
+
# ) -> None:
|
|
116
|
+
# """
|
|
117
|
+
# Update the next_page_data dictionary with the appropriate data needed to fetch the next page of records.
|
|
118
|
+
|
|
119
|
+
# This method has a very important job, which is to inform clearskies about how to make another API call to fetch the next
|
|
120
|
+
# page of records. The way this happens is by updating the `next_page_data` dictionary in place with whatever pagination
|
|
121
|
+
# information is necessary. Note that this relies on next_page_data being passed by reference, hence the need to update
|
|
122
|
+
# it in place. That means that you can do this:
|
|
123
|
+
|
|
124
|
+
# ```python
|
|
125
|
+
# next_page_data["some_key"] = "some_value"
|
|
126
|
+
# ```
|
|
127
|
+
|
|
128
|
+
# but if you do this:
|
|
129
|
+
|
|
130
|
+
# ```python
|
|
131
|
+
# next_page_data = {"some_key": "some_value"}
|
|
132
|
+
# ```
|
|
133
|
+
|
|
134
|
+
# Then things simply won't work.
|
|
135
|
+
# """
|
|
136
|
+
# # Different APIs generally have completely different ways of communicating pagination data, but one somewhat common
|
|
137
|
+
# # approach is to use a link header, so let's support that in the base class.
|
|
138
|
+
# if "link" not in response.headers:
|
|
139
|
+
# return
|
|
140
|
+
# next_link = [rel for rel in response.headers["link"].split(",") if 'rel="next"' in rel]
|
|
141
|
+
# if not next_link:
|
|
142
|
+
# return
|
|
143
|
+
# parsed_next_link = urllib.parse.urlparse(next_link[0].split(";")[0].strip(" <>"))
|
|
144
|
+
# query_parameters = urllib.parse.parse_qs(parsed_next_link.query)
|
|
145
|
+
# if self.pagination_parameter_name not in query_parameters:
|
|
146
|
+
# raise ValueError(
|
|
147
|
+
# f"Configuration error with {self.__class__.__name__}! I am configured to expect a pagination key of '{self.pagination_parameter_name}. However, when I was parsing the next link from a response to get the next pagination details, I could not find the designated pagination key. This likely means that backend.pagination_parameter_name is set to the wrong value. The link in question was "
|
|
148
|
+
# + parsed_next_link.geturl()
|
|
149
|
+
# )
|
|
150
|
+
# next_page_data[self.pagination_parameter_name] = query_parameters[self.pagination_parameter_name][0]
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import clearskies
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class GitlabDefaultAuth(clearskies.di.AdditionalConfigAutoImport):
|
|
5
|
+
def provide_gitlab_auth(self, environment: clearskies.Environment):
|
|
6
|
+
secret_key = environment.get("GITLAB_AUTH_KEY", True)
|
|
7
|
+
return clearskies.authentication.SecretBearer(secret_key=secret_key, header_prefix="Bearer ")
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import clearskies
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class GitlabDefaultUrl(clearskies.di.AdditionalConfigAutoImport):
|
|
5
|
+
def provide_gitlab_url(self, environment: clearskies.Environment):
|
|
6
|
+
gitlab_url = environment.get("GITLAB_URL", True)
|
|
7
|
+
return gitlab_url if gitlab_url else "https://gitlab.com/api/v4/"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from clearskies_gitlab.exceptions.gitlab_error import (
|
|
2
|
+
GitlabParamMissingError,
|
|
3
|
+
GitlabResourceError,
|
|
4
|
+
GitlabResponseError,
|
|
5
|
+
MethodNotImplementedError,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"GitlabParamMissingError",
|
|
10
|
+
"GitlabResourceError",
|
|
11
|
+
"GitlabResponseError",
|
|
12
|
+
"MethodNotImplementedError",
|
|
13
|
+
]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from clearskies.exceptions import ClientError
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class CredentialError(ClientError):
|
|
5
|
+
"""Throw exception if something goes wrong for fetching the credentials from Akeyless."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, key_name: str) -> None:
|
|
8
|
+
"""Create specific message for Credential Issue."""
|
|
9
|
+
super().__init__(f"Could not retrieve {key_name}")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class InvalidCredentialError(ClientError):
|
|
13
|
+
"""Throw exception if the token isn't valid anymore."""
|
|
14
|
+
|
|
15
|
+
def __init__(self) -> None:
|
|
16
|
+
"""Create specific message for InvalidCredentialError Issue."""
|
|
17
|
+
super().__init__("Gitlab token for was not valid - please contact Cimpress security and privacy")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class MethodNotImplementedError(NotImplementedError):
|
|
21
|
+
"""Error if Method is not implemented in the Gitlab api for endpoint."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, method: str, endpoint: str, version: str = "v1") -> None:
|
|
24
|
+
"""Create error with method and endpoint on version."""
|
|
25
|
+
super().__init__(f"Method: {method} is not implemented for {endpoint} in {version}.")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class GitlabResourceError(ValueError):
|
|
29
|
+
"""Error if resource could be found."""
|
|
30
|
+
|
|
31
|
+
def __init__(self, endpoint: str, resource_name: str) -> None:
|
|
32
|
+
"""Create error if resource name is not specified for endpoint."""
|
|
33
|
+
super().__init__(
|
|
34
|
+
f"The Gitlab API for endpoint {endpoint} requires searching by a column named {resource_name}, but it was missing in the query"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class GitlabResponseError(ValueError):
|
|
39
|
+
"""Error if response of Gitlab is wrong."""
|
|
40
|
+
|
|
41
|
+
def __init__(self, status_code: int, message: bytes) -> None:
|
|
42
|
+
"""Create error with request info."""
|
|
43
|
+
super().__init__(f"Failed request. Status code: {status_code}, message: {message.decode()}")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class GitlabParamMissingError(ValueError):
|
|
47
|
+
"""Error if param is missing."""
|
|
48
|
+
|
|
49
|
+
def __init__(self, param_name: str, table_name: str) -> None:
|
|
50
|
+
super().__init__(f"Must provide the {param_name} to add the member to when updating a {table_name}")
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from clearskies_gitlab.models import rest
|
|
4
|
+
from clearskies_gitlab.models.gitlab_cicd_variable import GitlabCICDVariable
|
|
5
|
+
from clearskies_gitlab.models.gitlab_gql_model import GitlabGqlModel
|
|
6
|
+
from clearskies_gitlab.models.gitlab_group import GitlabGroup
|
|
7
|
+
from clearskies_gitlab.models.gitlab_member import GitlabMember
|
|
8
|
+
from clearskies_gitlab.models.gitlab_project import GitlabProject
|
|
9
|
+
from clearskies_gitlab.models.gitlab_rest_model import GitlabRestModel
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"rest",
|
|
13
|
+
"GitlabGqlModel",
|
|
14
|
+
"GitlabGroup",
|
|
15
|
+
"GitlabMember",
|
|
16
|
+
"GitlabCICDVariable",
|
|
17
|
+
"GitlabProject",
|
|
18
|
+
"GitlabRestModel",
|
|
19
|
+
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections import OrderedDict
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from clearskies import Model
|
|
7
|
+
from clearskies.columns import Boolean, String
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class GitlabCICDVariable(Model):
|
|
11
|
+
"""Base model for groups ci/cd variables."""
|
|
12
|
+
|
|
13
|
+
id_column_name = "key"
|
|
14
|
+
|
|
15
|
+
key = String()
|
|
16
|
+
value = String()
|
|
17
|
+
description = String()
|
|
18
|
+
environment_scope = String()
|
|
19
|
+
variable_type = String()
|
|
20
|
+
masked = Boolean()
|
|
21
|
+
protected = Boolean()
|
|
22
|
+
hidden = Boolean()
|
|
23
|
+
raw = Boolean()
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections import OrderedDict
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from clearskies import Model
|
|
7
|
+
from clearskies.columns import Boolean, Datetime, Integer, Json, String
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class GitlabGroup(Model):
|
|
11
|
+
"""Base model for groups."""
|
|
12
|
+
|
|
13
|
+
id_column_name = "id"
|
|
14
|
+
|
|
15
|
+
id = String()
|
|
16
|
+
web_url = String()
|
|
17
|
+
name = String()
|
|
18
|
+
path = String()
|
|
19
|
+
description = String()
|
|
20
|
+
visibility = String()
|
|
21
|
+
share_with_group_lock = Boolean()
|
|
22
|
+
require_two_factor_authentication = Boolean()
|
|
23
|
+
two_factor_grace_period = Integer()
|
|
24
|
+
project_creation_level = String()
|
|
25
|
+
auto_devops_enabled = Boolean()
|
|
26
|
+
subgroup_creation_level = String()
|
|
27
|
+
emails_disabled = Boolean()
|
|
28
|
+
emails_enabled = Boolean()
|
|
29
|
+
mentions_disabled = String()
|
|
30
|
+
lfs_enabled = String()
|
|
31
|
+
math_rendering_limits_enabled = Boolean()
|
|
32
|
+
lock_math_rendering_limits_enabled = Boolean()
|
|
33
|
+
default_branch = String()
|
|
34
|
+
default_branch_protection = String()
|
|
35
|
+
default_branch_protection_defaults = String()
|
|
36
|
+
avatar_url = String()
|
|
37
|
+
request_access_enabled = Boolean()
|
|
38
|
+
full_name = String()
|
|
39
|
+
full_path = String()
|
|
40
|
+
created_at = Datetime()
|
|
41
|
+
parent_id = String()
|
|
42
|
+
organization_id = String()
|
|
43
|
+
shared_runners_setting = String()
|
|
44
|
+
custom_attributes = Json()
|
|
45
|
+
statistics = Json()
|
|
46
|
+
ldap_cn = String()
|
|
47
|
+
ldap_access = String()
|
|
48
|
+
ldap_group_links = Json()
|
|
49
|
+
saml_group_links = Json()
|
|
50
|
+
file_template_project_id = String()
|
|
51
|
+
marked_for_deletion_on = Datetime()
|
|
52
|
+
wiki_access_level = String()
|
|
53
|
+
repository_storage = String()
|
|
54
|
+
duo_features_enabled = Boolean()
|
|
55
|
+
lock_duo_features_enabled = Boolean()
|
|
56
|
+
shared_with_groups = Json()
|
|
57
|
+
runners_token = String()
|
|
58
|
+
enabled_git_access_protocol = String()
|
|
59
|
+
prevent_sharing_groups_outside_hierarchy = Boolean()
|
|
60
|
+
shared_runners_minutes_limit = Integer()
|
|
61
|
+
extra_shared_runners_minutes_limit = Integer()
|
|
62
|
+
prevent_forking_outside_group = Boolean()
|
|
63
|
+
service_access_tokens_expiration_enforced = Boolean()
|
|
64
|
+
membership_lock = Boolean()
|
|
65
|
+
ip_restriction_ranges = Json()
|
|
66
|
+
unique_project_download_limit = String()
|
|
67
|
+
unique_project_download_limit_interval_in_seconds = Integer()
|
|
68
|
+
unique_project_download_limit_alertlist = Json()
|
|
69
|
+
auto_ban_user_on_excessive_projects_download = Boolean()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections import OrderedDict
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from clearskies import Model
|
|
7
|
+
from clearskies.columns import Datetime, Email, Integer, Json, String
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class GitlabMember(Model):
|
|
11
|
+
"""Base model for group or project members."""
|
|
12
|
+
|
|
13
|
+
id_column_name = "id"
|
|
14
|
+
|
|
15
|
+
id = Integer()
|
|
16
|
+
username = String()
|
|
17
|
+
name = String()
|
|
18
|
+
state = String()
|
|
19
|
+
avatar_url = String()
|
|
20
|
+
access_level = Integer()
|
|
21
|
+
created_at = Datetime()
|
|
22
|
+
created_by = Json()
|
|
23
|
+
email = Email()
|
|
24
|
+
group_saml_identity = Json()
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections import OrderedDict
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from clearskies import Model
|
|
7
|
+
from clearskies.columns import Boolean, Datetime, Integer, Json, Select, String
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class GitlabNamespace(Model):
|
|
11
|
+
"""Base model for namespaces."""
|
|
12
|
+
|
|
13
|
+
id_column_name = "id"
|
|
14
|
+
|
|
15
|
+
id = String()
|
|
16
|
+
name = String()
|
|
17
|
+
path = String()
|
|
18
|
+
kind = Select(allowed_values=["group", "user"])
|
|
19
|
+
full_path = String()
|
|
20
|
+
avatar_url = String()
|
|
21
|
+
web_url = String()
|
|
22
|
+
billable_members_count = Integer()
|
|
23
|
+
plan = Select(allowed_values=["free", "premium", "ultimate", "bronze", "silver", "gold"])
|
|
24
|
+
end_date = Datetime()
|
|
25
|
+
trial_ends_on = Datetime()
|
|
26
|
+
trial = Boolean()
|
|
27
|
+
root_repository_size = Integer()
|
|
28
|
+
projects_count = Integer()
|
|
29
|
+
max_seats_used = Integer()
|
|
30
|
+
max_seats_used_changed_at = Datetime()
|
|
31
|
+
seats_in_use = Integer()
|
|
32
|
+
members_counts_with_descendants = Integer()
|