clear-skies-gitlab 2.0.4__py3-none-any.whl → 2.0.6__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.4.dist-info → clear_skies_gitlab-2.0.6.dist-info}/METADATA +1 -1
- {clear_skies_gitlab-2.0.4.dist-info → clear_skies_gitlab-2.0.6.dist-info}/RECORD +34 -34
- clearskies_gitlab/defaults/gitlab_default_auth.py +33 -2
- clearskies_gitlab/defaults/gitlab_default_host.py +31 -2
- clearskies_gitlab/rest/backends/gitlab_rest_backend.py +98 -80
- clearskies_gitlab/rest/gitlab_branch_rule.py +74 -1
- clearskies_gitlab/rest/gitlab_cicd_variable.py +78 -1
- clearskies_gitlab/rest/gitlab_member.py +80 -1
- clearskies_gitlab/rest/models/gitlab_rest_advanced_search.py +67 -1
- clearskies_gitlab/rest/models/gitlab_rest_advanced_search_blob.py +72 -1
- clearskies_gitlab/rest/models/gitlab_rest_current_user.py +134 -1
- clearskies_gitlab/rest/models/gitlab_rest_group.py +60 -1
- clearskies_gitlab/rest/models/gitlab_rest_group_access_token.py +102 -1
- clearskies_gitlab/rest/models/gitlab_rest_group_base.py +305 -1
- clearskies_gitlab/rest/models/gitlab_rest_group_member.py +64 -1
- clearskies_gitlab/rest/models/gitlab_rest_group_project.py +27 -1
- clearskies_gitlab/rest/models/gitlab_rest_group_search.py +30 -1
- clearskies_gitlab/rest/models/gitlab_rest_group_search_blob.py +27 -1
- clearskies_gitlab/rest/models/gitlab_rest_group_subgroup.py +54 -17
- clearskies_gitlab/rest/models/gitlab_rest_group_variable.py +44 -1
- clearskies_gitlab/rest/models/gitlab_rest_namespace.py +178 -1
- clearskies_gitlab/rest/models/gitlab_rest_project.py +501 -3
- clearskies_gitlab/rest/models/gitlab_rest_project_approval_config.py +90 -2
- clearskies_gitlab/rest/models/gitlab_rest_project_approval_rule.py +92 -1
- clearskies_gitlab/rest/models/gitlab_rest_project_member.py +62 -1
- clearskies_gitlab/rest/models/gitlab_rest_project_protected_branch.py +132 -1
- clearskies_gitlab/rest/models/gitlab_rest_project_repository_commit.py +144 -2
- clearskies_gitlab/rest/models/gitlab_rest_project_repository_commit_diff.py +89 -2
- clearskies_gitlab/rest/models/gitlab_rest_project_repository_contributor.py +68 -2
- clearskies_gitlab/rest/models/gitlab_rest_project_repository_file.py +90 -1
- clearskies_gitlab/rest/models/gitlab_rest_project_repository_file_raw.py +57 -3
- clearskies_gitlab/rest/models/gitlab_rest_project_variable.py +46 -1
- {clear_skies_gitlab-2.0.4.dist-info → clear_skies_gitlab-2.0.6.dist-info}/WHEEL +0 -0
- {clear_skies_gitlab-2.0.4.dist-info → clear_skies_gitlab-2.0.6.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clear-skies-gitlab
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.6
|
|
4
4
|
Summary: Gitlab module for Clearskies
|
|
5
5
|
Project-URL: Docs, https://https://clearskies.info/modules/clear-skies-gitlab
|
|
6
6
|
Project-URL: Repository, https://github.com/clearskies-py/gitlab
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
clearskies_gitlab/__init__.py,sha256=TlKrAfFOTW6YnQefxEQbUdnf_F3sVOvRKsG_6cfFAsk,123
|
|
2
2
|
clearskies_gitlab/defaults/__init__.py,sha256=t3Dfm98aoahHCepQnW1YBSVKgDz0QEp7hTrGL8XAcTE,341
|
|
3
|
-
clearskies_gitlab/defaults/gitlab_default_auth.py,sha256=
|
|
4
|
-
clearskies_gitlab/defaults/gitlab_default_host.py,sha256=
|
|
3
|
+
clearskies_gitlab/defaults/gitlab_default_auth.py,sha256=zSa8R0hgIYgj5DX_wPF7FyDqYjbAitepOoYC1_wCeqA,1566
|
|
4
|
+
clearskies_gitlab/defaults/gitlab_default_host.py,sha256=gi2qiZ5k28ER-TRpA7GYO4hPILUJxM0bFbxTIEas2V4,1326
|
|
5
5
|
clearskies_gitlab/defaults/gitlab_graphql_client.py,sha256=eIQ3efp2oYFuGSIGimZ1e5AC8TOTy1j8K26SU_AK-yU,609
|
|
6
6
|
clearskies_gitlab/exceptions/__init__.py,sha256=QUg8lVn91QMENpN_uZmYdNkhI1EjFAWN9X6cMKgKmtE,301
|
|
7
7
|
clearskies_gitlab/exceptions/gitlab_error.py,sha256=5hm8iYXnEfxxRkKPBXIq0v5mL1l5ZqaxlmUKnBjOe3g,2054
|
|
@@ -18,51 +18,51 @@ clearskies_gitlab/graphql/models/gitlab_group_reference.py,sha256=V3y3DxKMhUWWjX
|
|
|
18
18
|
clearskies_gitlab/graphql/models/gitlab_project.py,sha256=IBG38Rwks6A9aqC2Qlss_qWohNQ2oUHF64irwE3-mj8,641
|
|
19
19
|
clearskies_gitlab/graphql/models/gitlab_project_reference.py,sha256=Z5Hi991TFQip-1151XcP-_ITVHwWmJiTDTlqRoAsg0A,290
|
|
20
20
|
clearskies_gitlab/rest/__init__.py,sha256=KZyBO-7OCE_qgClt-eTOh8jYIJccKpcuXHZ4eZCpW-0,316
|
|
21
|
-
clearskies_gitlab/rest/gitlab_branch_rule.py,sha256=
|
|
22
|
-
clearskies_gitlab/rest/gitlab_cicd_variable.py,sha256=
|
|
23
|
-
clearskies_gitlab/rest/gitlab_member.py,sha256
|
|
21
|
+
clearskies_gitlab/rest/gitlab_branch_rule.py,sha256=9YqoudklWKUk3x51xPBJvabZCS4_KoOxGDTc3oyXLik,2376
|
|
22
|
+
clearskies_gitlab/rest/gitlab_cicd_variable.py,sha256=txuJM3GVcMcH06y7D33y4msYMWYTVE1GVitPuQNW--g,2608
|
|
23
|
+
clearskies_gitlab/rest/gitlab_member.py,sha256=-x5t5ZArHRZ_XgAvNRKPfdsGd2WYZpMfezh2mfO3fJc,2391
|
|
24
24
|
clearskies_gitlab/rest/backends/__init__.py,sha256=xUhpRXyB_FHhTsz94A2kviBlPzZfaKqIiHOhDrNg6Wc,115
|
|
25
|
-
clearskies_gitlab/rest/backends/gitlab_rest_backend.py,sha256=
|
|
25
|
+
clearskies_gitlab/rest/backends/gitlab_rest_backend.py,sha256=OpAYhLkoNmggM-6OZONjmV8BCV6r2wPlATMb2TxF_BQ,6345
|
|
26
26
|
clearskies_gitlab/rest/models/__init__.py,sha256=mcfdh04R8Fu5T-6Cz-Iy3CJ2LLttgkwBGd3Qp0Rtt6A,2750
|
|
27
|
-
clearskies_gitlab/rest/models/gitlab_rest_advanced_search.py,sha256=
|
|
28
|
-
clearskies_gitlab/rest/models/gitlab_rest_advanced_search_blob.py,sha256=
|
|
29
|
-
clearskies_gitlab/rest/models/gitlab_rest_current_user.py,sha256=
|
|
30
|
-
clearskies_gitlab/rest/models/gitlab_rest_group.py,sha256=
|
|
31
|
-
clearskies_gitlab/rest/models/gitlab_rest_group_access_token.py,sha256=
|
|
27
|
+
clearskies_gitlab/rest/models/gitlab_rest_advanced_search.py,sha256=NQYX9AH-MwT77oFvTrubZmaar7okN0HQU-fCQ6iQtjE,2964
|
|
28
|
+
clearskies_gitlab/rest/models/gitlab_rest_advanced_search_blob.py,sha256=jESJma3csPfrgV3KdlBZqtxIiZAd5MEKsdu7XNwBzbw,2472
|
|
29
|
+
clearskies_gitlab/rest/models/gitlab_rest_current_user.py,sha256=jR9z16rYilkmngGJnAs1ABODMd8corYHLW3V3S0buH0,3917
|
|
30
|
+
clearskies_gitlab/rest/models/gitlab_rest_group.py,sha256=9tNj5RRMXh05wG1XVlh8TTCStSgfuZ7eWYchTfyZp40,2907
|
|
31
|
+
clearskies_gitlab/rest/models/gitlab_rest_group_access_token.py,sha256=j_iByq4lKZ9sAhVTCBrNPf6ThtDanC8Y4cpA_F4iLtA,3294
|
|
32
32
|
clearskies_gitlab/rest/models/gitlab_rest_group_access_token_reference.py,sha256=GZnAOIgIDJCPR55ABD4bxPT--TUOnkVV1peQMtai2dU,358
|
|
33
|
-
clearskies_gitlab/rest/models/gitlab_rest_group_base.py,sha256=
|
|
34
|
-
clearskies_gitlab/rest/models/gitlab_rest_group_member.py,sha256=
|
|
33
|
+
clearskies_gitlab/rest/models/gitlab_rest_group_base.py,sha256=GON6nD600ZkenpMh4Y_sS5rXwo5l2vzMwiXtoIdn5hs,8435
|
|
34
|
+
clearskies_gitlab/rest/models/gitlab_rest_group_member.py,sha256=TkUIhH_4Cd9TrFjNVi657TMY1FjExPIM1ueXpKVaVNs,2323
|
|
35
35
|
clearskies_gitlab/rest/models/gitlab_rest_group_member_reference.py,sha256=XrhG_hiqGQf8vIosss2Vp4RWvNNtHxIn-TzXtPGQvgU,331
|
|
36
|
-
clearskies_gitlab/rest/models/gitlab_rest_group_project.py,sha256=
|
|
36
|
+
clearskies_gitlab/rest/models/gitlab_rest_group_project.py,sha256=bvUy7kRgWPaZocbxKcuqpfBxFdyxmDeOb02_klQiPVU,1281
|
|
37
37
|
clearskies_gitlab/rest/models/gitlab_rest_group_project_reference.py,sha256=fp45VWXMC_3inaep1GIS6ortIucZoxh-7xb7RnTl8DI,336
|
|
38
38
|
clearskies_gitlab/rest/models/gitlab_rest_group_reference.py,sha256=UiHQpQNuVM3WotCNEFIlEqLwXMdy-8YqYRil-S84MQI,292
|
|
39
|
-
clearskies_gitlab/rest/models/gitlab_rest_group_search.py,sha256=
|
|
40
|
-
clearskies_gitlab/rest/models/gitlab_rest_group_search_blob.py,sha256=
|
|
41
|
-
clearskies_gitlab/rest/models/gitlab_rest_group_subgroup.py,sha256=
|
|
39
|
+
clearskies_gitlab/rest/models/gitlab_rest_group_search.py,sha256=csQAVv93Y37oVk__agqEsC1mmbu0h68hpWG34VYJS0s,1466
|
|
40
|
+
clearskies_gitlab/rest/models/gitlab_rest_group_search_blob.py,sha256=kecmETgb-5EnekJDVfRHgIARvFQ46oSGTRZP1PPA7XI,1251
|
|
41
|
+
clearskies_gitlab/rest/models/gitlab_rest_group_subgroup.py,sha256=EGLEaOIzU3QpqOVk1SG9Npsx49mTVXIVr4Q_S6zzdLo,2727
|
|
42
42
|
clearskies_gitlab/rest/models/gitlab_rest_group_subgroup_reference.py,sha256=vFAlOmQ8wJswlcNGJ9zrrxidsFXC70hDfYNrNZ5VQ9g,341
|
|
43
|
-
clearskies_gitlab/rest/models/gitlab_rest_group_variable.py,sha256=
|
|
43
|
+
clearskies_gitlab/rest/models/gitlab_rest_group_variable.py,sha256=20vldlXL69Y52CT3ylxDBM429ga9sqmZvqdB1uGzM2w,1932
|
|
44
44
|
clearskies_gitlab/rest/models/gitlab_rest_group_variable_reference.py,sha256=rGgqrOY-HCxpsstDb1_Hy_KwPt6Z37xxIJnBRD9eXXw,341
|
|
45
|
-
clearskies_gitlab/rest/models/gitlab_rest_namespace.py,sha256=
|
|
46
|
-
clearskies_gitlab/rest/models/gitlab_rest_project.py,sha256=
|
|
47
|
-
clearskies_gitlab/rest/models/gitlab_rest_project_approval_config.py,sha256=
|
|
45
|
+
clearskies_gitlab/rest/models/gitlab_rest_namespace.py,sha256=nTqDb2CDFAa1SBFnGZxw-s4M8DJZS7yqyPI16poY0Ew,5610
|
|
46
|
+
clearskies_gitlab/rest/models/gitlab_rest_project.py,sha256=PcI08WIkv9c4H-b0d8qsxfYMKLGSAT8Ms9mbul0g9IQ,15019
|
|
47
|
+
clearskies_gitlab/rest/models/gitlab_rest_project_approval_config.py,sha256=sCCQklMwr7oOvGD1y5PDvmZXaUeX8H1wFdW-CetMoL8,3737
|
|
48
48
|
clearskies_gitlab/rest/models/gitlab_rest_project_approval_config_reference.py,sha256=Gfs1iFo8VOH8llpcdOquZ7uNA5qFv6LNaGx-glTC3AM,383
|
|
49
|
-
clearskies_gitlab/rest/models/gitlab_rest_project_approval_rule.py,sha256=
|
|
49
|
+
clearskies_gitlab/rest/models/gitlab_rest_project_approval_rule.py,sha256=Cc5rk6KbBhibtIgUVQ7LT9WBrIXI3AepFcYsdmvzw00,3710
|
|
50
50
|
clearskies_gitlab/rest/models/gitlab_rest_project_approval_rule_reference.py,sha256=VTWBcv225UQyxFr8ZdTpgEdXCiTerYGIbYyGdt1j-tc,373
|
|
51
|
-
clearskies_gitlab/rest/models/gitlab_rest_project_member.py,sha256=
|
|
51
|
+
clearskies_gitlab/rest/models/gitlab_rest_project_member.py,sha256=QtcjOu799gKcfVUi9XJqEXQi2CrSZFxB_TBmbtbl6GM,2208
|
|
52
52
|
clearskies_gitlab/rest/models/gitlab_rest_project_member_reference.py,sha256=nNz0Qm5Q5Esyugk9IiNe3Y2Q9SNwWPiLxpOQuiMNAMk,341
|
|
53
|
-
clearskies_gitlab/rest/models/gitlab_rest_project_protected_branch.py,sha256=
|
|
53
|
+
clearskies_gitlab/rest/models/gitlab_rest_project_protected_branch.py,sha256=8rn3MRHefmB9XCLornF-uQ5PcWWlZrGaEYWgt07Quso,5177
|
|
54
54
|
clearskies_gitlab/rest/models/gitlab_rest_project_protected_branch_reference.py,sha256=TCP892aJDxn_YKR0wJFfOTfkwOHoDAc6uBvrDYO5fl8,388
|
|
55
55
|
clearskies_gitlab/rest/models/gitlab_rest_project_reference.py,sha256=Rg3-fjN9WHoIsubKO3Un1trqPU1-ZoZAkE6jW33P568,302
|
|
56
|
-
clearskies_gitlab/rest/models/gitlab_rest_project_repository_commit.py,sha256=
|
|
57
|
-
clearskies_gitlab/rest/models/gitlab_rest_project_repository_commit_diff.py,sha256=
|
|
58
|
-
clearskies_gitlab/rest/models/gitlab_rest_project_repository_contributor.py,sha256=
|
|
56
|
+
clearskies_gitlab/rest/models/gitlab_rest_project_repository_commit.py,sha256=qGTeQHpj0_HbHZ6XnMtRcHSeuCW2BoYIpSNiLuCRlEc,4564
|
|
57
|
+
clearskies_gitlab/rest/models/gitlab_rest_project_repository_commit_diff.py,sha256=ICrM-UuVuygVG7VfbPhjBBy1XwSaL7_J5Cydin8S0Wg,2967
|
|
58
|
+
clearskies_gitlab/rest/models/gitlab_rest_project_repository_contributor.py,sha256=CaEsOuajhAblbxnSzVFgiWA8sVSB8-lZkYCCIbNkcKk,2808
|
|
59
59
|
clearskies_gitlab/rest/models/gitlab_rest_project_repository_contributor_reference.py,sha256=yEIO424xhYcN7YpyAVXseMVET48RZ0hpu_WOOZTf3LA,418
|
|
60
|
-
clearskies_gitlab/rest/models/gitlab_rest_project_repository_file.py,sha256=
|
|
61
|
-
clearskies_gitlab/rest/models/gitlab_rest_project_repository_file_raw.py,sha256=
|
|
60
|
+
clearskies_gitlab/rest/models/gitlab_rest_project_repository_file.py,sha256=ZhSsSh7GFgwVarKEHUU1yAEuiBW3rVf45vWqwNJh7bg,3220
|
|
61
|
+
clearskies_gitlab/rest/models/gitlab_rest_project_repository_file_raw.py,sha256=XL4b3EexuzcEXcsP1sDu74Nxpjlpb7jM71tM_OymxwI,2464
|
|
62
62
|
clearskies_gitlab/rest/models/gitlab_rest_project_repository_file_reference.py,sha256=WiK7aOhBZD_8HRvvlTQ6oWk3hXOJAyfEKdqmCIUIM9M,383
|
|
63
|
-
clearskies_gitlab/rest/models/gitlab_rest_project_variable.py,sha256=
|
|
63
|
+
clearskies_gitlab/rest/models/gitlab_rest_project_variable.py,sha256=D8FjgGafJOUQhM62hSWgYbNDABrF4mBNigY8lWBH7f4,2097
|
|
64
64
|
clearskies_gitlab/rest/models/gitlab_rest_project_variable_reference.py,sha256=6P-9TbvhYMZGoBMM-BFFDFKsN40LEXd9FKYNTFpNayU,351
|
|
65
|
-
clear_skies_gitlab-2.0.
|
|
66
|
-
clear_skies_gitlab-2.0.
|
|
67
|
-
clear_skies_gitlab-2.0.
|
|
68
|
-
clear_skies_gitlab-2.0.
|
|
65
|
+
clear_skies_gitlab-2.0.6.dist-info/METADATA,sha256=c1pjM3LUEpeNy-vYwIdwHQWvIu96ukgO-Un5rck5oss,2143
|
|
66
|
+
clear_skies_gitlab-2.0.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
67
|
+
clear_skies_gitlab-2.0.6.dist-info/licenses/LICENSE,sha256=S7gzTni6Tje0gBaQnXxs5BXdrBBKQ9eAVWjMHZccST8,1069
|
|
68
|
+
clear_skies_gitlab-2.0.6.dist-info/RECORD,,
|
|
@@ -2,9 +2,40 @@ import clearskies
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class GitlabDefaultAuth(clearskies.di.AdditionalConfigAutoImport):
|
|
5
|
-
"""
|
|
5
|
+
"""
|
|
6
|
+
Dependency injection provider for GitLab authentication.
|
|
7
|
+
|
|
8
|
+
This class automatically provides GitLab authentication credentials to the
|
|
9
|
+
dependency injection container. It reads the authentication token from the
|
|
10
|
+
`GITLAB_AUTH_KEY` environment variable and configures a Bearer token
|
|
11
|
+
authentication handler.
|
|
12
|
+
|
|
13
|
+
The authentication is used by the GitlabRestBackend to authenticate API
|
|
14
|
+
requests to GitLab.
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
# Set environment variable with your GitLab personal access token
|
|
18
|
+
# export GITLAB_AUTH_KEY=glpat-xxxxxxxxxxxxxxxxxxxx
|
|
19
|
+
|
|
20
|
+
from clearskies_gitlab.rest.backends import GitlabRestBackend
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MyModel(clearskies.Model):
|
|
24
|
+
backend = GitlabRestBackend()
|
|
25
|
+
# Will automatically use the configured authentication
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The token should be a GitLab Personal Access Token (PAT) or Project/Group
|
|
29
|
+
Access Token with appropriate scopes for the API operations you need to perform.
|
|
30
|
+
"""
|
|
6
31
|
|
|
7
32
|
def provide_gitlab_auth(self, environment: clearskies.Environment):
|
|
8
|
-
"""
|
|
33
|
+
"""
|
|
34
|
+
Provide the GitLab authentication handler from environment.
|
|
35
|
+
|
|
36
|
+
Reads the `GITLAB_AUTH_KEY` environment variable and returns a
|
|
37
|
+
SecretBearer authentication handler configured with the `Bearer ` prefix
|
|
38
|
+
as required by the GitLab API.
|
|
39
|
+
"""
|
|
9
40
|
secret_key = environment.get("GITLAB_AUTH_KEY", True)
|
|
10
41
|
return clearskies.authentication.SecretBearer(secret_key=secret_key, header_prefix="Bearer ")
|
|
@@ -2,9 +2,38 @@ import clearskies
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class GitlabDefaultHost(clearskies.di.AdditionalConfigAutoImport):
|
|
5
|
-
"""
|
|
5
|
+
"""
|
|
6
|
+
Dependency injection provider for the GitLab host URL.
|
|
7
|
+
|
|
8
|
+
This class automatically provides the GitLab host URL to the dependency
|
|
9
|
+
injection container. It reads the host from the `GITLAB_HOST` environment
|
|
10
|
+
variable, falling back to `https://gitlab.com/` if not set.
|
|
11
|
+
|
|
12
|
+
This is used by the GitlabRestBackend and other GitLab-related classes
|
|
13
|
+
to determine which GitLab instance to connect to.
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
# Set environment variable for self-hosted GitLab
|
|
17
|
+
# export GITLAB_HOST=https://gitlab.mycompany.com/
|
|
18
|
+
|
|
19
|
+
# Or use the default gitlab.com
|
|
20
|
+
# (no environment variable needed)
|
|
21
|
+
|
|
22
|
+
from clearskies_gitlab.rest.backends import GitlabRestBackend
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class MyModel(clearskies.Model):
|
|
26
|
+
backend = GitlabRestBackend()
|
|
27
|
+
# Will automatically use the configured host
|
|
28
|
+
```
|
|
29
|
+
"""
|
|
6
30
|
|
|
7
31
|
def provide_gitlab_host(self, environment: clearskies.Environment):
|
|
8
|
-
"""
|
|
32
|
+
"""
|
|
33
|
+
Provide the GitLab host URL from environment or default.
|
|
34
|
+
|
|
35
|
+
Reads the `GITLAB_HOST` environment variable. If not set or empty,
|
|
36
|
+
returns the default GitLab.com URL.
|
|
37
|
+
"""
|
|
9
38
|
gitlab_host = environment.get("GITLAB_HOST", True)
|
|
10
39
|
return gitlab_host if gitlab_host else "https://gitlab.com/"
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import urllib
|
|
4
3
|
from typing import TYPE_CHECKING, Any
|
|
4
|
+
from urllib import parse
|
|
5
5
|
|
|
6
6
|
from clearskies import configs
|
|
7
7
|
from clearskies.backends import ApiBackend
|
|
8
8
|
from clearskies.decorators import parameters_to_properties
|
|
9
9
|
from clearskies.di import inject
|
|
10
10
|
from clearskies.query import Query
|
|
11
|
+
from clearskies.query.result import CountQueryResult
|
|
11
12
|
from requests.structures import CaseInsensitiveDict
|
|
12
13
|
|
|
13
14
|
if TYPE_CHECKING:
|
|
@@ -16,14 +17,77 @@ if TYPE_CHECKING:
|
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class GitlabRestBackend(ApiBackend):
|
|
19
|
-
"""
|
|
20
|
+
"""
|
|
21
|
+
Backend for interacting with the GitLab REST API.
|
|
20
22
|
|
|
23
|
+
This backend extends the clearskies ApiBackend to provide GitLab-specific functionality
|
|
24
|
+
for making REST API calls to GitLab.com or self-hosted GitLab instances. It handles
|
|
25
|
+
authentication, pagination, and response mapping automatically.
|
|
26
|
+
|
|
27
|
+
The backend uses dependency injection to obtain the GitLab host URL and authentication
|
|
28
|
+
credentials, making it easy to configure for different environments.
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import clearskies
|
|
32
|
+
from clearskies_gitlab.rest.backends import GitlabRestBackend
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class MyGitlabModel(clearskies.Model):
|
|
36
|
+
backend = GitlabRestBackend()
|
|
37
|
+
id_column_name = "id"
|
|
38
|
+
|
|
39
|
+
id = clearskies.columns.Integer()
|
|
40
|
+
name = clearskies.columns.String()
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The backend automatically constructs the base URL using the configured GitLab host
|
|
44
|
+
and appends `/api/v4` for the REST API version.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
"""
|
|
48
|
+
Whether this backend supports count operations.
|
|
49
|
+
|
|
50
|
+
GitLab REST API supports counting via the `x-total` response header,
|
|
51
|
+
so this is set to True.
|
|
52
|
+
"""
|
|
53
|
+
can_count = True
|
|
54
|
+
|
|
55
|
+
"""
|
|
56
|
+
The GitLab host URL injected from the dependency container.
|
|
57
|
+
|
|
58
|
+
This is typically set via the `GITLAB_HOST` environment variable or through
|
|
59
|
+
explicit configuration. Defaults to `https://gitlab.com/` if not specified.
|
|
60
|
+
"""
|
|
21
61
|
gitlab_host = inject.ByName("gitlab_host", cache=True) # type: ignore[assignment]
|
|
62
|
+
|
|
63
|
+
"""
|
|
64
|
+
The authentication handler injected from the dependency container.
|
|
65
|
+
|
|
66
|
+
This is typically configured via the `GITLAB_AUTH_KEY` environment variable
|
|
67
|
+
which provides a bearer token for API authentication.
|
|
68
|
+
"""
|
|
22
69
|
authentication = inject.ByName("gitlab_auth", cache=False) # type: ignore[assignment]
|
|
70
|
+
|
|
71
|
+
"""
|
|
72
|
+
The requests handler for making HTTP calls.
|
|
73
|
+
"""
|
|
23
74
|
requests = inject.Requests()
|
|
75
|
+
|
|
24
76
|
_auth_headers: dict[str, str] = {}
|
|
25
77
|
|
|
78
|
+
"""
|
|
79
|
+
A mapping from API response field names to model field names.
|
|
80
|
+
|
|
81
|
+
Use this to handle cases where the GitLab API returns fields with different
|
|
82
|
+
names than your model expects.
|
|
83
|
+
"""
|
|
26
84
|
api_to_model_map = configs.AnyDict(default={})
|
|
85
|
+
|
|
86
|
+
"""
|
|
87
|
+
The name of the query parameter used for pagination.
|
|
88
|
+
|
|
89
|
+
GitLab uses `page` for page-based pagination.
|
|
90
|
+
"""
|
|
27
91
|
pagination_parameter_name = configs.String(default="page")
|
|
28
92
|
|
|
29
93
|
@parameters_to_properties
|
|
@@ -43,58 +107,54 @@ class GitlabRestBackend(ApiBackend):
|
|
|
43
107
|
@property
|
|
44
108
|
def base_url(self) -> str:
|
|
45
109
|
"""
|
|
46
|
-
|
|
110
|
+
Construct the base URL for GitLab API requests.
|
|
47
111
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
112
|
+
Combines the configured GitLab host with the API version path (`/api/v4`).
|
|
113
|
+
The host URL is automatically trimmed of trailing slashes to ensure
|
|
114
|
+
proper URL construction.
|
|
51
115
|
"""
|
|
52
116
|
return f"{self.gitlab_host.rstrip('/')}/api/v4"
|
|
53
117
|
|
|
54
118
|
def count_method(self, query: Query) -> str:
|
|
55
|
-
"""
|
|
119
|
+
"""
|
|
120
|
+
Return the HTTP method to use when requesting a record count.
|
|
121
|
+
|
|
122
|
+
GitLab supports HEAD requests for efficient counting without
|
|
123
|
+
returning the full response body.
|
|
124
|
+
"""
|
|
56
125
|
return "HEAD"
|
|
57
126
|
|
|
58
|
-
def count(self, query: Query) ->
|
|
59
|
-
"""
|
|
127
|
+
def count(self, query: Query) -> CountQueryResult:
|
|
128
|
+
"""
|
|
129
|
+
Return the count of records matching the query.
|
|
130
|
+
|
|
131
|
+
Makes a HEAD request to the GitLab API and extracts the total count
|
|
132
|
+
from the `x-total` response header. Returns a CountQueryResult object
|
|
133
|
+
as required by the clearskies backend interface.
|
|
134
|
+
"""
|
|
60
135
|
self.check_query(query)
|
|
61
136
|
(url, method, body, headers) = self.build_records_request(query)
|
|
62
137
|
response = self.execute_request(url, self.count_method(query), json=body, headers=headers)
|
|
63
|
-
|
|
138
|
+
count = self._map_count_response(response.headers)
|
|
139
|
+
return CountQueryResult(count=count)
|
|
64
140
|
|
|
65
141
|
def _map_count_response(self, headers: CaseInsensitiveDict[str]) -> int:
|
|
142
|
+
"""Extract the total record count from GitLab response headers."""
|
|
66
143
|
return int(headers.get("x-total", 0))
|
|
67
144
|
|
|
68
|
-
# def map_records_response(
|
|
69
|
-
# self, response_data: Any, query: Query, query_data: dict[str, Any] | None = None
|
|
70
|
-
# ) -> list[dict[str, Any]]:
|
|
71
|
-
# """Map the response data to model records with support for nested fields."""
|
|
72
|
-
# if query_data is None:
|
|
73
|
-
# query_data = {}
|
|
74
|
-
|
|
75
|
-
# columns = query.model_class.get_columns()
|
|
76
|
-
# result = []
|
|
77
|
-
|
|
78
|
-
# # Handle list response
|
|
79
|
-
# if isinstance(response_data, list):
|
|
80
|
-
# for item in response_data:
|
|
81
|
-
# if not isinstance(item, dict):
|
|
82
|
-
# continue
|
|
83
|
-
# mapped = self.check_dict_and_map_to_model(item, columns, query_data)
|
|
84
|
-
# if mapped:
|
|
85
|
-
# result.append(mapped)
|
|
86
|
-
# # Handle single object response
|
|
87
|
-
# elif isinstance(response_data, dict):
|
|
88
|
-
# mapped = self.check_dict_and_map_to_model(response_data, columns, query_data)
|
|
89
|
-
# if mapped:
|
|
90
|
-
# result.append(mapped)
|
|
91
|
-
|
|
92
|
-
# return result
|
|
93
|
-
|
|
94
145
|
def conditions_to_request_parameters(
|
|
95
146
|
self, query: Query, used_routing_parameters: list[str]
|
|
96
147
|
) -> tuple[str, dict[str, str], dict[str, Any]]:
|
|
97
|
-
"""
|
|
148
|
+
"""
|
|
149
|
+
Convert query conditions to GitLab API request parameters.
|
|
150
|
+
|
|
151
|
+
Transforms clearskies query conditions into URL parameters suitable for
|
|
152
|
+
the GitLab REST API. Only equality conditions are supported; other operators
|
|
153
|
+
will raise a ValueError.
|
|
154
|
+
|
|
155
|
+
If a condition targets the model's ID column, it will be URL-encoded and
|
|
156
|
+
returned as the route_id for path-based lookups.
|
|
157
|
+
"""
|
|
98
158
|
route_id = ""
|
|
99
159
|
|
|
100
160
|
url_parameters = {}
|
|
@@ -106,50 +166,8 @@ class GitlabRestBackend(ApiBackend):
|
|
|
106
166
|
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."
|
|
107
167
|
)
|
|
108
168
|
if condition.column_name == query.model_class.id_column_name:
|
|
109
|
-
route_id =
|
|
169
|
+
route_id = parse.quote_plus(condition.values[0]).replace("+", "%20")
|
|
110
170
|
continue
|
|
111
171
|
url_parameters[condition.column_name] = condition.values[0]
|
|
112
172
|
|
|
113
173
|
return (route_id, url_parameters, {})
|
|
114
|
-
|
|
115
|
-
# def set_next_page_data_from_response(
|
|
116
|
-
# self,
|
|
117
|
-
# next_page_data: dict[str, Any],
|
|
118
|
-
# query: Query,
|
|
119
|
-
# response: requests.Response,
|
|
120
|
-
# ) -> None:
|
|
121
|
-
# """
|
|
122
|
-
# Update the next_page_data dictionary with the appropriate data needed to fetch the next page of records.
|
|
123
|
-
|
|
124
|
-
# This method has a very important job, which is to inform clearskies about how to make another API call to fetch the next
|
|
125
|
-
# page of records. The way this happens is by updating the `next_page_data` dictionary in place with whatever pagination
|
|
126
|
-
# information is necessary. Note that this relies on next_page_data being passed by reference, hence the need to update
|
|
127
|
-
# it in place. That means that you can do this:
|
|
128
|
-
|
|
129
|
-
# ```python
|
|
130
|
-
# next_page_data["some_key"] = "some_value"
|
|
131
|
-
# ```
|
|
132
|
-
|
|
133
|
-
# but if you do this:
|
|
134
|
-
|
|
135
|
-
# ```python
|
|
136
|
-
# next_page_data = {"some_key": "some_value"}
|
|
137
|
-
# ```
|
|
138
|
-
|
|
139
|
-
# Then things simply won't work.
|
|
140
|
-
# """
|
|
141
|
-
# # Different APIs generally have completely different ways of communicating pagination data, but one somewhat common
|
|
142
|
-
# # approach is to use a link header, so let's support that in the base class.
|
|
143
|
-
# if "link" not in response.headers:
|
|
144
|
-
# return
|
|
145
|
-
# next_link = [rel for rel in response.headers["link"].split(",") if 'rel="next"' in rel]
|
|
146
|
-
# if not next_link:
|
|
147
|
-
# return
|
|
148
|
-
# parsed_next_link = urllib.parse.urlparse(next_link[0].split(";")[0].strip(" <>"))
|
|
149
|
-
# query_parameters = urllib.parse.parse_qs(parsed_next_link.query)
|
|
150
|
-
# if self.pagination_parameter_name not in query_parameters:
|
|
151
|
-
# raise ValueError(
|
|
152
|
-
# 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 "
|
|
153
|
-
# + parsed_next_link.geturl()
|
|
154
|
-
# )
|
|
155
|
-
# next_page_data[self.pagination_parameter_name] = query_parameters[self.pagination_parameter_name][0]
|
|
@@ -5,17 +5,90 @@ from clearskies.columns import Boolean, Datetime, Integer, Json, String
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class GitlabBranchRule(Model):
|
|
8
|
-
"""
|
|
8
|
+
"""
|
|
9
|
+
Model representing a GitLab branch protection rule.
|
|
9
10
|
|
|
11
|
+
Branch rules in GitLab define protection settings for branches, controlling
|
|
12
|
+
who can push, merge, and unprotect branches. This model maps to the GitLab
|
|
13
|
+
REST API response for protected branches.
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from clearskies_gitlab.rest import GitlabBranchRule
|
|
17
|
+
from clearskies_gitlab.rest.backends import GitlabRestBackend
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ProjectBranchRule(GitlabBranchRule):
|
|
21
|
+
backend = GitlabRestBackend()
|
|
22
|
+
table_name = "projects/{project_id}/protected_branches"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Fetch all protected branches for a project
|
|
26
|
+
rules = ProjectBranchRule.where(project_id="my-project").all()
|
|
27
|
+
for rule in rules:
|
|
28
|
+
print(f"Branch: {rule.name}, Protected: {rule.protected}")
|
|
29
|
+
```
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
"""
|
|
33
|
+
The unique identifier for the branch rule.
|
|
34
|
+
"""
|
|
10
35
|
id = Integer()
|
|
36
|
+
|
|
37
|
+
"""
|
|
38
|
+
The name or pattern of the protected branch (e.g., `main`, `release/*`).
|
|
39
|
+
"""
|
|
11
40
|
name = String()
|
|
41
|
+
|
|
42
|
+
"""
|
|
43
|
+
Whether the branch is protected.
|
|
44
|
+
"""
|
|
12
45
|
protected = Boolean()
|
|
46
|
+
|
|
47
|
+
"""
|
|
48
|
+
Whether developers are allowed to push to the branch.
|
|
49
|
+
"""
|
|
13
50
|
developers_can_push = Boolean()
|
|
51
|
+
|
|
52
|
+
"""
|
|
53
|
+
Whether developers are allowed to merge into the branch.
|
|
54
|
+
"""
|
|
14
55
|
developers_can_merge = Boolean()
|
|
56
|
+
|
|
57
|
+
"""
|
|
58
|
+
Whether the current user can push to the branch.
|
|
59
|
+
"""
|
|
15
60
|
can_push = Boolean()
|
|
61
|
+
|
|
62
|
+
"""
|
|
63
|
+
Whether this is the default branch of the repository.
|
|
64
|
+
"""
|
|
16
65
|
default = Boolean()
|
|
66
|
+
|
|
67
|
+
"""
|
|
68
|
+
The timestamp when the branch rule was created.
|
|
69
|
+
"""
|
|
17
70
|
created_at = Datetime()
|
|
71
|
+
|
|
72
|
+
"""
|
|
73
|
+
The timestamp when the branch rule was last updated.
|
|
74
|
+
"""
|
|
18
75
|
updated_at = Datetime()
|
|
76
|
+
|
|
77
|
+
"""
|
|
78
|
+
Whether code owner approval is required for merges to this branch.
|
|
79
|
+
"""
|
|
19
80
|
code_owner_approval_required = Boolean()
|
|
81
|
+
|
|
82
|
+
"""
|
|
83
|
+
JSON array of access levels that can unprotect the branch.
|
|
84
|
+
|
|
85
|
+
Each entry contains information about who can remove protection from this branch.
|
|
86
|
+
"""
|
|
20
87
|
unprotect_access_levels = Json()
|
|
88
|
+
|
|
89
|
+
"""
|
|
90
|
+
JSON array of access levels that can push to the branch.
|
|
91
|
+
|
|
92
|
+
Each entry contains information about who can push directly to this branch.
|
|
93
|
+
"""
|
|
21
94
|
push_access_levels = Json()
|
|
@@ -5,16 +5,93 @@ from clearskies.columns import Boolean, String
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class GitlabCICDVariable(Model):
|
|
8
|
-
"""
|
|
8
|
+
"""
|
|
9
|
+
Model representing a GitLab CI/CD variable.
|
|
10
|
+
|
|
11
|
+
CI/CD variables in GitLab are used to store values that can be used in
|
|
12
|
+
CI/CD pipelines. They can be defined at the project, group, or instance level.
|
|
13
|
+
This model maps to the GitLab REST API response for CI/CD variables.
|
|
14
|
+
|
|
15
|
+
Note that the `key` field is used as the unique identifier (`id_column_name`)
|
|
16
|
+
since GitLab identifies variables by their key name.
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from clearskies_gitlab.rest import GitlabCICDVariable
|
|
20
|
+
from clearskies_gitlab.rest.backends import GitlabRestBackend
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ProjectVariable(GitlabCICDVariable):
|
|
24
|
+
backend = GitlabRestBackend()
|
|
25
|
+
table_name = "projects/{project_id}/variables"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# Fetch all CI/CD variables for a project
|
|
29
|
+
variables = ProjectVariable.where(project_id="my-project").all()
|
|
30
|
+
for var in variables:
|
|
31
|
+
print(f"Key: {var.key}, Protected: {var.protected}")
|
|
32
|
+
```
|
|
33
|
+
"""
|
|
9
34
|
|
|
10
35
|
id_column_name = "key"
|
|
11
36
|
|
|
37
|
+
"""
|
|
38
|
+
The name of the variable, used as the unique identifier.
|
|
39
|
+
"""
|
|
12
40
|
key = String()
|
|
41
|
+
|
|
42
|
+
"""
|
|
43
|
+
The value stored in the variable.
|
|
44
|
+
|
|
45
|
+
This may be masked in API responses if the `masked` flag is set.
|
|
46
|
+
"""
|
|
13
47
|
value = String()
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
A human-readable description of the variable's purpose.
|
|
51
|
+
"""
|
|
14
52
|
description = String()
|
|
53
|
+
|
|
54
|
+
"""
|
|
55
|
+
The environment scope for the variable.
|
|
56
|
+
|
|
57
|
+
Determines which environments the variable is available in.
|
|
58
|
+
Use `*` for all environments or specify a specific environment name.
|
|
59
|
+
"""
|
|
15
60
|
environment_scope = String()
|
|
61
|
+
|
|
62
|
+
"""
|
|
63
|
+
The type of variable.
|
|
64
|
+
|
|
65
|
+
Can be `env_var` for environment variables or `file` for file-type variables.
|
|
66
|
+
"""
|
|
16
67
|
variable_type = String()
|
|
68
|
+
|
|
69
|
+
"""
|
|
70
|
+
Whether the variable value is masked in job logs.
|
|
71
|
+
|
|
72
|
+
When true, the variable value will be hidden in CI/CD job output.
|
|
73
|
+
"""
|
|
17
74
|
masked = Boolean()
|
|
75
|
+
|
|
76
|
+
"""
|
|
77
|
+
Whether the variable is only available in protected branches/tags.
|
|
78
|
+
|
|
79
|
+
When true, the variable is only exposed to pipelines running on
|
|
80
|
+
protected branches or tags.
|
|
81
|
+
"""
|
|
18
82
|
protected = Boolean()
|
|
83
|
+
|
|
84
|
+
"""
|
|
85
|
+
Whether the variable is hidden from the UI.
|
|
86
|
+
|
|
87
|
+
Hidden variables cannot be viewed or edited through the GitLab interface.
|
|
88
|
+
"""
|
|
19
89
|
hidden = Boolean()
|
|
90
|
+
|
|
91
|
+
"""
|
|
92
|
+
Whether the variable value should be treated as raw (no variable expansion).
|
|
93
|
+
|
|
94
|
+
When true, the variable value is used as-is without expanding any
|
|
95
|
+
embedded variable references.
|
|
96
|
+
"""
|
|
20
97
|
raw = Boolean()
|