clear-skies-gitlab 2.0.4__py3-none-any.whl → 2.0.5__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.
Files changed (34) hide show
  1. {clear_skies_gitlab-2.0.4.dist-info → clear_skies_gitlab-2.0.5.dist-info}/METADATA +1 -1
  2. {clear_skies_gitlab-2.0.4.dist-info → clear_skies_gitlab-2.0.5.dist-info}/RECORD +34 -34
  3. clearskies_gitlab/defaults/gitlab_default_auth.py +33 -2
  4. clearskies_gitlab/defaults/gitlab_default_host.py +31 -2
  5. clearskies_gitlab/rest/backends/gitlab_rest_backend.py +98 -80
  6. clearskies_gitlab/rest/gitlab_branch_rule.py +74 -1
  7. clearskies_gitlab/rest/gitlab_cicd_variable.py +78 -1
  8. clearskies_gitlab/rest/gitlab_member.py +80 -1
  9. clearskies_gitlab/rest/models/gitlab_rest_advanced_search.py +67 -1
  10. clearskies_gitlab/rest/models/gitlab_rest_advanced_search_blob.py +72 -1
  11. clearskies_gitlab/rest/models/gitlab_rest_current_user.py +134 -1
  12. clearskies_gitlab/rest/models/gitlab_rest_group.py +60 -1
  13. clearskies_gitlab/rest/models/gitlab_rest_group_access_token.py +102 -1
  14. clearskies_gitlab/rest/models/gitlab_rest_group_base.py +305 -1
  15. clearskies_gitlab/rest/models/gitlab_rest_group_member.py +64 -1
  16. clearskies_gitlab/rest/models/gitlab_rest_group_project.py +27 -1
  17. clearskies_gitlab/rest/models/gitlab_rest_group_search.py +30 -1
  18. clearskies_gitlab/rest/models/gitlab_rest_group_search_blob.py +27 -1
  19. clearskies_gitlab/rest/models/gitlab_rest_group_subgroup.py +54 -17
  20. clearskies_gitlab/rest/models/gitlab_rest_group_variable.py +44 -1
  21. clearskies_gitlab/rest/models/gitlab_rest_namespace.py +178 -1
  22. clearskies_gitlab/rest/models/gitlab_rest_project.py +501 -3
  23. clearskies_gitlab/rest/models/gitlab_rest_project_approval_config.py +72 -1
  24. clearskies_gitlab/rest/models/gitlab_rest_project_approval_rule.py +92 -1
  25. clearskies_gitlab/rest/models/gitlab_rest_project_member.py +62 -1
  26. clearskies_gitlab/rest/models/gitlab_rest_project_protected_branch.py +132 -1
  27. clearskies_gitlab/rest/models/gitlab_rest_project_repository_commit.py +144 -2
  28. clearskies_gitlab/rest/models/gitlab_rest_project_repository_commit_diff.py +89 -2
  29. clearskies_gitlab/rest/models/gitlab_rest_project_repository_contributor.py +68 -2
  30. clearskies_gitlab/rest/models/gitlab_rest_project_repository_file.py +90 -1
  31. clearskies_gitlab/rest/models/gitlab_rest_project_repository_file_raw.py +57 -3
  32. clearskies_gitlab/rest/models/gitlab_rest_project_variable.py +46 -1
  33. {clear_skies_gitlab-2.0.4.dist-info → clear_skies_gitlab-2.0.5.dist-info}/WHEEL +0 -0
  34. {clear_skies_gitlab-2.0.4.dist-info → clear_skies_gitlab-2.0.5.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.4
3
+ Version: 2.0.5
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=w8w7LcekC38tbD-fuv5liDnvo4UsBxKVF7YZoTuzUus,456
4
- clearskies_gitlab/defaults/gitlab_default_host.py,sha256=wlyj0u-nbUqkkZQnZFgMXKH32nNlTABfCL6iWA88V6E,411
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=D8HptQg9BdKAtPtVkRYbt1sga0R9eErECYDLLuvSa7A,569
22
- clearskies_gitlab/rest/gitlab_cicd_variable.py,sha256=398-5SPlMk3-Zyu1dZTbpM9YCP2qNOsnydku3hiWvlc,446
23
- clearskies_gitlab/rest/gitlab_member.py,sha256=o1G652wbIImd8rz9NJQeAlJaxAftNt-6u7quoLYFwh0,487
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=nAZe8JRD1xMUNNoinOBWAGWv__S3Jko9d7OhXUlTeQk,6672
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=iFxCGDaqzRxl2a9g91P7zpj2ZAxuRbYoSiz_hsXMavY,883
28
- clearskies_gitlab/rest/models/gitlab_rest_advanced_search_blob.py,sha256=R3DFxbAcm3Em8S6dZ51EG6m-OSaM-BQmuo035SHV5NU,628
29
- clearskies_gitlab/rest/models/gitlab_rest_current_user.py,sha256=KrOfehkusr_FlB8Q4-IOU51Go5ULgykBDi9v883w80k,1135
30
- clearskies_gitlab/rest/models/gitlab_rest_group.py,sha256=iJgz78APzdlK9TOv0OmqVU_3qg-lJ3cdUBkMjyqhYho,1410
31
- clearskies_gitlab/rest/models/gitlab_rest_group_access_token.py,sha256=83tvO01CQktMwLm1Is9fIf_IkGR6zFIvvELwjkdSr4s,843
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=lnX37uxnIu1aWmGjDuT1ZVk9NeHQwmnFRjS_2Wjq53s,3102
34
- clearskies_gitlab/rest/models/gitlab_rest_group_member.py,sha256=CLkslCom4Deo2c3GdkoM8cuVYLOsvfreYzOUm64DTNs,707
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=33hEMN08aIsl4-tcIgNmruGLRYr0XqIuD9nQZ3Xs_CY,415
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=VgpGDRwe3UhY2AXfqWpGYYY6ghUhoDNKJqeLsrNtwcA,506
40
- clearskies_gitlab/rest/models/gitlab_rest_group_search_blob.py,sha256=_tIkwwDzJF9nGV0LL9fVqY5Tn4SSBXNg1C0dKlUQ-oM,353
41
- clearskies_gitlab/rest/models/gitlab_rest_group_subgroup.py,sha256=x0h_alIV3QFbslXIlqHC48HAOmmFw5T96XAwWh31-uA,1937
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=ixs4o6BV31sepagW46d4ipunn-szKNCHtlqKB6IxG5o,607
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=AIh56mDeB8LtrKVhWEtZ1Gop_V9enBdObjpKfK5b-0g,2484
46
- clearskies_gitlab/rest/models/gitlab_rest_project.py,sha256=Nc6u-R3Pb4NO6pZUYtZ6RYkygqizyiTybIkpFN47aXM,6687
47
- clearskies_gitlab/rest/models/gitlab_rest_project_approval_config.py,sha256=E1Yhk4kWQfWA1Peyml0yrJuJeqkFfMvYffQ7vmfNmoc,1099
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=W3rsRx6YSlpcy6k5vZ-cvNW36rtZ15pcI150vgGkB-c,3172
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=W1bHWl1kv9Avs3oBtOAowVpVB0-pe2mXGDFyQuxUnJM,1249
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=StXXvQ4Hs5VV2ngEMGvhdKwbXwlOu1ABbeQ-rfM3r48,717
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=95peeiCkBQCCsYWidIWWNAywBnPh1w9NUzVtrOIQwHY,1031
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=h9Q3b3YtFXpCC_OVqckohm1tCZwGCfojBL3qo6I3oSw,1532
57
- clearskies_gitlab/rest/models/gitlab_rest_project_repository_commit_diff.py,sha256=xUxnA6TGOfwSraojid06V1wXOF-Tqp8JXw0a7Kg50nc,894
58
- clearskies_gitlab/rest/models/gitlab_rest_project_repository_contributor.py,sha256=QEvGxMOHIKFPoxjo9OzESaJ_syHij9o_dubFvhacIJo,971
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=0yYNi2zgUjl4UAjUvDaJ92wIutxOEpzBKNE-7dBN3ZQ,1112
61
- clearskies_gitlab/rest/models/gitlab_rest_project_repository_file_raw.py,sha256=oExYzvAT6mUxY5mkw-nkAUZh-MmWy5lXq9UcFRst7nA,895
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=rfmk38ndgtdzoaoUFxRDPLhrRc5JWuNa2B2mWO1q4aM,813
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.4.dist-info/METADATA,sha256=Qub88NvHlz3Yj4cmBZ-AZnGlWg_9O7ZDKCl_yhbnJfA,2143
66
- clear_skies_gitlab-2.0.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
67
- clear_skies_gitlab-2.0.4.dist-info/licenses/LICENSE,sha256=S7gzTni6Tje0gBaQnXxs5BXdrBBKQ9eAVWjMHZccST8,1069
68
- clear_skies_gitlab-2.0.4.dist-info/RECORD,,
65
+ clear_skies_gitlab-2.0.5.dist-info/METADATA,sha256=9p7QHC--LHWZChCcTMEJWP7qcb0TrNZ8k43a07Aq_iw,2143
66
+ clear_skies_gitlab-2.0.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
67
+ clear_skies_gitlab-2.0.5.dist-info/licenses/LICENSE,sha256=S7gzTni6Tje0gBaQnXxs5BXdrBBKQ9eAVWjMHZccST8,1069
68
+ clear_skies_gitlab-2.0.5.dist-info/RECORD,,
@@ -2,9 +2,40 @@ import clearskies
2
2
 
3
3
 
4
4
  class GitlabDefaultAuth(clearskies.di.AdditionalConfigAutoImport):
5
- """Provide default Gitlab authentication from environment."""
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
- """Provide the Gitlab authentication from environment."""
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
- """Provide default GitLab Host from environment."""
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
- """Provide the GitLab host from environment or default."""
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
- """Backend for Gitlab.com."""
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
- Docstring for base_url.
110
+ Construct the base URL for GitLab API requests.
47
111
 
48
- :param self: Description
49
- :return: Description
50
- :rtype: str
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
- """Return the request method to use when making a request for a record count."""
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) -> int:
59
- """Return the count of records matching the query."""
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
- return self._map_count_response(response.headers)
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
- """Convert query conditions to request parameters."""
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 = urllib.parse.quote_plus(condition.values[0]).replace("+", "%20")
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
- """Model for GitLab branch rules."""
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
- """Base model for groups ci/cd variables."""
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()