gitlabform 5.0.0rc1__tar.gz → 5.0.2__tar.gz
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.
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/PKG-INFO +11 -11
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/README.md +1 -1
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/configuration/core.py +1 -1
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/core.py +6 -3
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/branches_processor.py +45 -17
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform.egg-info/PKG-INFO +11 -11
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform.egg-info/SOURCES.txt +0 -1
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform.egg-info/requires.txt +8 -8
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/pyproject.toml +11 -11
- gitlabform-5.0.0rc1/gitlabform/processors/single_entity_processor.py +0 -59
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/LICENSE +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/__init__.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/configuration/__init__.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/configuration/common.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/configuration/groups.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/configuration/projects.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/configuration/transform.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/constants.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/__init__.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/commits.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/group_badges.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/group_ldap_links.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/groups.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/merge_requests.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/pipelines.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/project_badges.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/project_deploy_keys.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/project_merge_requests_approvals.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/project_protected_environments.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/projects.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/python_gitlab.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/variables.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/lists/__init__.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/lists/filter.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/lists/groups.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/lists/projects.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/output.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/__init__.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/abstract_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/application/__init__.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/application/application_settings_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/defining_keys.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/__init__.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_badges_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_hooks_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_labels_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_ldap_links_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_members_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_push_rules_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_saml_links_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_settings_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_variables_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/multiple_entities_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/__init__.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/badges_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/deploy_keys_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/files_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/hooks_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/integrations_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/job_token_scope_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/members_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/merge_requests_approval_rules.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/merge_requests_approvals.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/project_labels_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/project_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/project_push_rules_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/project_security_settings.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/project_settings_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/project_variables_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/remote_mirrors_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/resource_groups_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/schedules_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/tags_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/shared/__init__.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/shared/protected_environments_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/util/__init__.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/util/decorators.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/util/difference_logger.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/util/labels_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/util/variables_processor.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/run.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/util.py +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform.egg-info/dependency_links.txt +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform.egg-info/entry_points.txt +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform.egg-info/top_level.txt +0 -0
- {gitlabform-5.0.0rc1 → gitlabform-5.0.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gitlabform
|
|
3
|
-
Version: 5.0.
|
|
3
|
+
Version: 5.0.2
|
|
4
4
|
Summary: 🏗 Specialized configuration as a code tool for GitLab projects, groups and more using hierarchical configuration written in YAML
|
|
5
5
|
Author: Greg Dubicki and Contributors
|
|
6
6
|
Project-URL: Homepage, https://gitlabform.github.io/gitlabform/
|
|
@@ -17,10 +17,10 @@ Classifier: Operating System :: POSIX :: Linux
|
|
|
17
17
|
Classifier: Operating System :: MacOS
|
|
18
18
|
Classifier: Operating System :: Microsoft :: Windows
|
|
19
19
|
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
20
|
-
Requires-Python: >=3.
|
|
20
|
+
Requires-Python: >=3.12.0
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
|
-
Requires-Dist: certifi==2026.
|
|
23
|
+
Requires-Dist: certifi==2026.2.25
|
|
24
24
|
Requires-Dist: cli-ui==0.19.0
|
|
25
25
|
Requires-Dist: ez-yaml==1.2.0
|
|
26
26
|
Requires-Dist: Jinja2==3.1.6
|
|
@@ -28,23 +28,23 @@ Requires-Dist: luddite==1.0.4
|
|
|
28
28
|
Requires-Dist: MarkupSafe==3.0.3
|
|
29
29
|
Requires-Dist: mergedeep==1.3.4
|
|
30
30
|
Requires-Dist: packaging==26.0
|
|
31
|
-
Requires-Dist: python-gitlab==8.
|
|
32
|
-
Requires-Dist: python-gitlab[graphql]==8.
|
|
31
|
+
Requires-Dist: python-gitlab==8.1.0
|
|
32
|
+
Requires-Dist: python-gitlab[graphql]==8.1.0
|
|
33
33
|
Requires-Dist: requests==2.32.5
|
|
34
34
|
Requires-Dist: ruamel.yaml==0.17.21
|
|
35
35
|
Requires-Dist: yamlpath==3.8.2
|
|
36
36
|
Provides-Extra: test
|
|
37
|
-
Requires-Dist: coverage==7.13.
|
|
38
|
-
Requires-Dist: cryptography==46.0.
|
|
39
|
-
Requires-Dist: deepdiff==8.6.
|
|
37
|
+
Requires-Dist: coverage==7.13.5; extra == "test"
|
|
38
|
+
Requires-Dist: cryptography==46.0.5; extra == "test"
|
|
39
|
+
Requires-Dist: deepdiff==8.6.2; extra == "test"
|
|
40
40
|
Requires-Dist: mypy==1.19.1; extra == "test"
|
|
41
41
|
Requires-Dist: mypy-extensions==1.1.0; extra == "test"
|
|
42
42
|
Requires-Dist: pre-commit==2.21.0; extra == "test"
|
|
43
43
|
Requires-Dist: pytest==9.0.2; extra == "test"
|
|
44
|
-
Requires-Dist: pytest-cov==7.
|
|
44
|
+
Requires-Dist: pytest-cov==7.1.0; extra == "test"
|
|
45
45
|
Requires-Dist: pytest-rerunfailures==16.1; extra == "test"
|
|
46
46
|
Requires-Dist: types-requests==2.32.4.20260107; extra == "test"
|
|
47
|
-
Requires-Dist: types-setuptools==
|
|
47
|
+
Requires-Dist: types-setuptools==82.0.0.20260210; extra == "test"
|
|
48
48
|
Requires-Dist: xkcdpass==1.30.0; extra == "test"
|
|
49
49
|
Provides-Extra: docs
|
|
50
50
|
Requires-Dist: mkdocs; extra == "docs"
|
|
@@ -56,7 +56,7 @@ Dynamic: license-file
|
|
|
56
56
|
[](https://pepy.tech/project/gitlabform)
|
|
57
57
|
[](https://github.com/psf/black)
|
|
58
58
|
[](https://codecov.io/gh/gitlabform/gitlabform)
|
|
59
|
-
[](https://security.snyk.io/package/pip/gitlabform)
|
|
60
60
|
|
|
61
61
|
<img src="https://raw.githubusercontent.com/gitlabform/gitlabform/main/docs/images/gitlabform-logo.png" width="600px" alt="logo">
|
|
62
62
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://pepy.tech/project/gitlabform)
|
|
4
4
|
[](https://github.com/psf/black)
|
|
5
5
|
[](https://codecov.io/gh/gitlabform/gitlabform)
|
|
6
|
-
[](https://security.snyk.io/package/pip/gitlabform)
|
|
7
7
|
|
|
8
8
|
<img src="https://raw.githubusercontent.com/gitlabform/gitlabform/main/docs/images/gitlabform-logo.png" width="600px" alt="logo">
|
|
9
9
|
|
|
@@ -66,7 +66,7 @@ class ConfigurationCore(ABC):
|
|
|
66
66
|
# we are NOT checking for the existence of non-empty 'projects_and_groups' key here
|
|
67
67
|
# as it would break using GitLabForm as a library
|
|
68
68
|
|
|
69
|
-
except FileNotFoundError, OSError:
|
|
69
|
+
except (FileNotFoundError, OSError):
|
|
70
70
|
raise ConfigFileNotFoundException(config_path)
|
|
71
71
|
|
|
72
72
|
except Exception as e:
|
|
@@ -72,9 +72,12 @@ class GitLabCore:
|
|
|
72
72
|
)
|
|
73
73
|
|
|
74
74
|
try:
|
|
75
|
-
|
|
76
|
-
verbose(
|
|
77
|
-
|
|
75
|
+
version_response = self._make_requests_to_api("version")
|
|
76
|
+
verbose(
|
|
77
|
+
f"Connected to GitLab version: {version_response['version']} ({version_response['revision']}), Enterprise Edition: {version_response['enterprise']}"
|
|
78
|
+
)
|
|
79
|
+
self.version = version_response["version"]
|
|
80
|
+
self.enterprise = version_response["enterprise"]
|
|
78
81
|
|
|
79
82
|
current_user = self._make_requests_to_api("user")
|
|
80
83
|
if current_user.get("is_admin", False):
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/branches_processor.py
RENAMED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
from typing import Optional
|
|
1
|
+
from typing import Optional, Any
|
|
2
|
+
|
|
2
3
|
from cli_ui import info, warning, error, fatal, debug as verbose
|
|
3
4
|
from gitlab import (
|
|
4
5
|
GitlabGetError,
|
|
5
6
|
GitlabDeleteError,
|
|
6
|
-
|
|
7
|
+
GitlabOperationError,
|
|
7
8
|
)
|
|
8
9
|
from gitlab.v4.objects import Project, ProjectProtectedBranch
|
|
9
10
|
|
|
10
11
|
from gitlabform.constants import EXIT_INVALID_INPUT, EXIT_PROCESSING_ERROR
|
|
11
|
-
from gitlabform.gitlab import GitLab
|
|
12
|
+
from gitlabform.gitlab import GitLab
|
|
12
13
|
from gitlabform.processors.abstract_processor import AbstractProcessor
|
|
13
14
|
|
|
14
15
|
|
|
@@ -80,10 +81,13 @@ class BranchesProcessor(AbstractProcessor):
|
|
|
80
81
|
return
|
|
81
82
|
|
|
82
83
|
# https://docs.gitlab.com/api/protected_branches/#update-a-protected-branch was only introduced after 15.6
|
|
83
|
-
# for user's on older versions of Gitlab
|
|
84
|
+
# for user's on older versions of Gitlab or Community Edition (https://gitlab.com/rluna-gitlab/gitlab-ce/-/work_items/37)
|
|
85
|
+
# We need to unprotect and then reprotect the branch to apply the
|
|
84
86
|
# defined configuration
|
|
85
|
-
if self.gitlab.is_version_less_than("15.6.0"):
|
|
86
|
-
self.
|
|
87
|
+
if self.gitlab.is_version_less_than("15.6.0") or (self.gitlab.enterprise == False):
|
|
88
|
+
self.process_branch_config_gitlab_under_15_6_0_or_ce(
|
|
89
|
+
branch_config, branch_name, project, protected_branch
|
|
90
|
+
)
|
|
87
91
|
return
|
|
88
92
|
|
|
89
93
|
# For later Gitlab versions we dynamically generate the data to send to the update endpoint based on the
|
|
@@ -116,7 +120,7 @@ class BranchesProcessor(AbstractProcessor):
|
|
|
116
120
|
verbose("Creating data to update merge_access_levels as necessary")
|
|
117
121
|
merge_access_items_patch_data = self.build_patch_request_data(
|
|
118
122
|
transformed_access_levels=transformed_branch_config.get("merge_access_levels"),
|
|
119
|
-
existing_records=tuple(protected_branch
|
|
123
|
+
existing_records=tuple(self._get_list_attribute(protected_branch, "merge_access_levels")),
|
|
120
124
|
)
|
|
121
125
|
if len(merge_access_items_patch_data) > 0:
|
|
122
126
|
protected_branch_api_patch_data["allowed_to_merge"] = merge_access_items_patch_data
|
|
@@ -124,16 +128,18 @@ class BranchesProcessor(AbstractProcessor):
|
|
|
124
128
|
verbose("Creating data to update push_access_levels as necessary")
|
|
125
129
|
push_access_items_patch_data = self.build_patch_request_data(
|
|
126
130
|
transformed_access_levels=transformed_branch_config.get("push_access_levels"),
|
|
127
|
-
existing_records=tuple(protected_branch
|
|
131
|
+
existing_records=tuple(self._get_list_attribute(protected_branch, "push_access_levels")),
|
|
128
132
|
)
|
|
129
133
|
if len(push_access_items_patch_data) > 0:
|
|
130
134
|
protected_branch_api_patch_data["allowed_to_push"] = push_access_items_patch_data
|
|
131
135
|
|
|
132
136
|
verbose("Creating data to update unprotect_access_levels as necessary")
|
|
137
|
+
|
|
133
138
|
unprotect_access_items_patch_data = self.build_patch_request_data(
|
|
134
139
|
transformed_access_levels=transformed_branch_config.get("unprotect_access_levels"),
|
|
135
|
-
existing_records=tuple(protected_branch
|
|
140
|
+
existing_records=tuple(self._get_list_attribute(protected_branch, "unprotect_access_levels")),
|
|
136
141
|
)
|
|
142
|
+
|
|
137
143
|
if len(unprotect_access_items_patch_data) > 0:
|
|
138
144
|
protected_branch_api_patch_data["allowed_to_unprotect"] = unprotect_access_items_patch_data
|
|
139
145
|
|
|
@@ -146,9 +152,9 @@ class BranchesProcessor(AbstractProcessor):
|
|
|
146
152
|
info(f"Removing branch protection for {branch_name}")
|
|
147
153
|
self.unprotect_branch(protected_branch)
|
|
148
154
|
|
|
149
|
-
def
|
|
155
|
+
def process_branch_config_gitlab_under_15_6_0_or_ce(self, branch_config, branch_name, project, protected_branch):
|
|
150
156
|
"""
|
|
151
|
-
Processes the branches configuration for gitlab version 15.6.0 or
|
|
157
|
+
Processes the branches configuration for gitlab version <=15.6.0 or Community Edition,
|
|
152
158
|
first checking if the branch needs to be updated, if it does, then the branch will be unprotected prior to being
|
|
153
159
|
reprotected with the YAML configuration.
|
|
154
160
|
"""
|
|
@@ -186,7 +192,7 @@ class BranchesProcessor(AbstractProcessor):
|
|
|
186
192
|
project.protectedbranches.update(branch_name, branch_config)
|
|
187
193
|
else:
|
|
188
194
|
project.protectedbranches.create({"name": branch_name, **branch_config})
|
|
189
|
-
except
|
|
195
|
+
except GitlabOperationError as e:
|
|
190
196
|
message = f"Protecting branch '{branch_name}' failed! Error '{e.error_message}"
|
|
191
197
|
|
|
192
198
|
if self.strict:
|
|
@@ -374,15 +380,21 @@ class BranchesProcessor(AbstractProcessor):
|
|
|
374
380
|
matching_item_to_be_created = None
|
|
375
381
|
|
|
376
382
|
for item in patch_data:
|
|
377
|
-
|
|
383
|
+
# We prioritize user_id and group_id matches over access_level.
|
|
384
|
+
# This avoids ambiguity because a user/group record from GitLab also contains an access_level.
|
|
385
|
+
# If we matched by access_level first, we might incorrectly pair a specific user's rule
|
|
386
|
+
# with a generic role-based rule from the config.
|
|
387
|
+
if existing_records_user_id is not None and item.get("user_id") == existing_records_user_id:
|
|
388
|
+
matching_item_to_be_created = item
|
|
389
|
+
break
|
|
390
|
+
elif existing_records_group_id is not None and item.get("group_id") == existing_records_group_id:
|
|
391
|
+
matching_item_to_be_created = item
|
|
392
|
+
break
|
|
393
|
+
elif (
|
|
378
394
|
existing_records_access_level is not None
|
|
379
395
|
and item.get("access_level") == existing_records_access_level
|
|
380
396
|
):
|
|
381
397
|
matching_item_to_be_created = item
|
|
382
|
-
elif existing_records_user_id is not None and item.get("user_id") == existing_records_user_id:
|
|
383
|
-
matching_item_to_be_created = item
|
|
384
|
-
elif existing_records_group_id is not None and item.get("group_id") == existing_records_group_id:
|
|
385
|
-
matching_item_to_be_created = item
|
|
386
398
|
|
|
387
399
|
if matching_item_to_be_created is not None:
|
|
388
400
|
# If we found an existing item matching one that has been configured, remove the item
|
|
@@ -436,3 +448,19 @@ class BranchesProcessor(AbstractProcessor):
|
|
|
436
448
|
https://docs.gitlab.com/user/project/repository/branches/protected/#use-wildcard-rules
|
|
437
449
|
"""
|
|
438
450
|
return "*" in branch
|
|
451
|
+
|
|
452
|
+
@staticmethod
|
|
453
|
+
def _get_list_attribute(protected_branch: ProjectProtectedBranch, attribute_name: str) -> list[Any]:
|
|
454
|
+
"""
|
|
455
|
+
Gets list attribute such as unprotect_access_levels, merge_access_levels, push_access_levels, etc.
|
|
456
|
+
Uses the python-gitlab attributes raw dict rather than direct parameter to gracefully handle when an attribute
|
|
457
|
+
is not present in the API response.
|
|
458
|
+
For example in CE: unprotect_access_levels is not returned on the protected_branch, so trying to access directly
|
|
459
|
+
throws a runtime-exception
|
|
460
|
+
"""
|
|
461
|
+
existing_list_value: list[Any] = []
|
|
462
|
+
# Get from the "attributes" as this is the raw dict
|
|
463
|
+
existing_attr = protected_branch.attributes.get(attribute_name)
|
|
464
|
+
if existing_attr is not None:
|
|
465
|
+
existing_list_value = existing_attr
|
|
466
|
+
return existing_list_value
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gitlabform
|
|
3
|
-
Version: 5.0.
|
|
3
|
+
Version: 5.0.2
|
|
4
4
|
Summary: 🏗 Specialized configuration as a code tool for GitLab projects, groups and more using hierarchical configuration written in YAML
|
|
5
5
|
Author: Greg Dubicki and Contributors
|
|
6
6
|
Project-URL: Homepage, https://gitlabform.github.io/gitlabform/
|
|
@@ -17,10 +17,10 @@ Classifier: Operating System :: POSIX :: Linux
|
|
|
17
17
|
Classifier: Operating System :: MacOS
|
|
18
18
|
Classifier: Operating System :: Microsoft :: Windows
|
|
19
19
|
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
20
|
-
Requires-Python: >=3.
|
|
20
|
+
Requires-Python: >=3.12.0
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
|
-
Requires-Dist: certifi==2026.
|
|
23
|
+
Requires-Dist: certifi==2026.2.25
|
|
24
24
|
Requires-Dist: cli-ui==0.19.0
|
|
25
25
|
Requires-Dist: ez-yaml==1.2.0
|
|
26
26
|
Requires-Dist: Jinja2==3.1.6
|
|
@@ -28,23 +28,23 @@ Requires-Dist: luddite==1.0.4
|
|
|
28
28
|
Requires-Dist: MarkupSafe==3.0.3
|
|
29
29
|
Requires-Dist: mergedeep==1.3.4
|
|
30
30
|
Requires-Dist: packaging==26.0
|
|
31
|
-
Requires-Dist: python-gitlab==8.
|
|
32
|
-
Requires-Dist: python-gitlab[graphql]==8.
|
|
31
|
+
Requires-Dist: python-gitlab==8.1.0
|
|
32
|
+
Requires-Dist: python-gitlab[graphql]==8.1.0
|
|
33
33
|
Requires-Dist: requests==2.32.5
|
|
34
34
|
Requires-Dist: ruamel.yaml==0.17.21
|
|
35
35
|
Requires-Dist: yamlpath==3.8.2
|
|
36
36
|
Provides-Extra: test
|
|
37
|
-
Requires-Dist: coverage==7.13.
|
|
38
|
-
Requires-Dist: cryptography==46.0.
|
|
39
|
-
Requires-Dist: deepdiff==8.6.
|
|
37
|
+
Requires-Dist: coverage==7.13.5; extra == "test"
|
|
38
|
+
Requires-Dist: cryptography==46.0.5; extra == "test"
|
|
39
|
+
Requires-Dist: deepdiff==8.6.2; extra == "test"
|
|
40
40
|
Requires-Dist: mypy==1.19.1; extra == "test"
|
|
41
41
|
Requires-Dist: mypy-extensions==1.1.0; extra == "test"
|
|
42
42
|
Requires-Dist: pre-commit==2.21.0; extra == "test"
|
|
43
43
|
Requires-Dist: pytest==9.0.2; extra == "test"
|
|
44
|
-
Requires-Dist: pytest-cov==7.
|
|
44
|
+
Requires-Dist: pytest-cov==7.1.0; extra == "test"
|
|
45
45
|
Requires-Dist: pytest-rerunfailures==16.1; extra == "test"
|
|
46
46
|
Requires-Dist: types-requests==2.32.4.20260107; extra == "test"
|
|
47
|
-
Requires-Dist: types-setuptools==
|
|
47
|
+
Requires-Dist: types-setuptools==82.0.0.20260210; extra == "test"
|
|
48
48
|
Requires-Dist: xkcdpass==1.30.0; extra == "test"
|
|
49
49
|
Provides-Extra: docs
|
|
50
50
|
Requires-Dist: mkdocs; extra == "docs"
|
|
@@ -56,7 +56,7 @@ Dynamic: license-file
|
|
|
56
56
|
[](https://pepy.tech/project/gitlabform)
|
|
57
57
|
[](https://github.com/psf/black)
|
|
58
58
|
[](https://codecov.io/gh/gitlabform/gitlabform)
|
|
59
|
-
[](https://security.snyk.io/package/pip/gitlabform)
|
|
60
60
|
|
|
61
61
|
<img src="https://raw.githubusercontent.com/gitlabform/gitlabform/main/docs/images/gitlabform-logo.png" width="600px" alt="logo">
|
|
62
62
|
|
|
@@ -41,7 +41,6 @@ gitlabform/processors/__init__.py
|
|
|
41
41
|
gitlabform/processors/abstract_processor.py
|
|
42
42
|
gitlabform/processors/defining_keys.py
|
|
43
43
|
gitlabform/processors/multiple_entities_processor.py
|
|
44
|
-
gitlabform/processors/single_entity_processor.py
|
|
45
44
|
gitlabform/processors/application/__init__.py
|
|
46
45
|
gitlabform/processors/application/application_settings_processor.py
|
|
47
46
|
gitlabform/processors/group/__init__.py
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
certifi==2026.
|
|
1
|
+
certifi==2026.2.25
|
|
2
2
|
cli-ui==0.19.0
|
|
3
3
|
ez-yaml==1.2.0
|
|
4
4
|
Jinja2==3.1.6
|
|
@@ -6,8 +6,8 @@ luddite==1.0.4
|
|
|
6
6
|
MarkupSafe==3.0.3
|
|
7
7
|
mergedeep==1.3.4
|
|
8
8
|
packaging==26.0
|
|
9
|
-
python-gitlab==8.
|
|
10
|
-
python-gitlab[graphql]==8.
|
|
9
|
+
python-gitlab==8.1.0
|
|
10
|
+
python-gitlab[graphql]==8.1.0
|
|
11
11
|
requests==2.32.5
|
|
12
12
|
ruamel.yaml==0.17.21
|
|
13
13
|
yamlpath==3.8.2
|
|
@@ -17,15 +17,15 @@ mkdocs
|
|
|
17
17
|
mkdocs-material
|
|
18
18
|
|
|
19
19
|
[test]
|
|
20
|
-
coverage==7.13.
|
|
21
|
-
cryptography==46.0.
|
|
22
|
-
deepdiff==8.6.
|
|
20
|
+
coverage==7.13.5
|
|
21
|
+
cryptography==46.0.5
|
|
22
|
+
deepdiff==8.6.2
|
|
23
23
|
mypy==1.19.1
|
|
24
24
|
mypy-extensions==1.1.0
|
|
25
25
|
pre-commit==2.21.0
|
|
26
26
|
pytest==9.0.2
|
|
27
|
-
pytest-cov==7.
|
|
27
|
+
pytest-cov==7.1.0
|
|
28
28
|
pytest-rerunfailures==16.1
|
|
29
29
|
types-requests==2.32.4.20260107
|
|
30
|
-
types-setuptools==
|
|
30
|
+
types-setuptools==82.0.0.20260210
|
|
31
31
|
xkcdpass==1.30.0
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "gitlabform"
|
|
7
|
-
version = "5.0.
|
|
7
|
+
version = "5.0.2"
|
|
8
8
|
authors = [{ name = "Greg Dubicki and Contributors" }]
|
|
9
9
|
description = "🏗 Specialized configuration as a code tool for GitLab projects, groups and more using hierarchical configuration written in YAML"
|
|
10
10
|
keywords = ["cli", "yaml", "gitlab", "configuration-as-code"]
|
|
@@ -21,9 +21,9 @@ classifiers = [
|
|
|
21
21
|
"Operating System :: Microsoft :: Windows",
|
|
22
22
|
"Topic :: Software Development :: Version Control :: Git",
|
|
23
23
|
]
|
|
24
|
-
requires-python = ">=3.
|
|
24
|
+
requires-python = ">=3.12.0"
|
|
25
25
|
dependencies = [
|
|
26
|
-
"certifi==2026.
|
|
26
|
+
"certifi==2026.2.25",
|
|
27
27
|
"cli-ui==0.19.0",
|
|
28
28
|
"ez-yaml==1.2.0",
|
|
29
29
|
"Jinja2==3.1.6",
|
|
@@ -31,8 +31,8 @@ dependencies = [
|
|
|
31
31
|
"MarkupSafe==3.0.3",
|
|
32
32
|
"mergedeep==1.3.4",
|
|
33
33
|
"packaging==26.0",
|
|
34
|
-
"python-gitlab==8.
|
|
35
|
-
"python-gitlab[graphql]==8.
|
|
34
|
+
"python-gitlab==8.1.0",
|
|
35
|
+
"python-gitlab[graphql]==8.1.0",
|
|
36
36
|
"requests==2.32.5",
|
|
37
37
|
"ruamel.yaml==0.17.21",
|
|
38
38
|
"yamlpath==3.8.2",
|
|
@@ -50,17 +50,17 @@ content-type = "text/markdown"
|
|
|
50
50
|
|
|
51
51
|
[project.optional-dependencies]
|
|
52
52
|
test = [
|
|
53
|
-
"coverage==7.13.
|
|
54
|
-
"cryptography==46.0.
|
|
55
|
-
"deepdiff==8.6.
|
|
53
|
+
"coverage==7.13.5",
|
|
54
|
+
"cryptography==46.0.5",
|
|
55
|
+
"deepdiff==8.6.2",
|
|
56
56
|
"mypy==1.19.1",
|
|
57
57
|
"mypy-extensions==1.1.0",
|
|
58
58
|
"pre-commit==2.21.0",
|
|
59
59
|
"pytest==9.0.2",
|
|
60
|
-
"pytest-cov==7.
|
|
60
|
+
"pytest-cov==7.1.0",
|
|
61
61
|
"pytest-rerunfailures==16.1",
|
|
62
62
|
"types-requests==2.32.4.20260107",
|
|
63
|
-
"types-setuptools==
|
|
63
|
+
"types-setuptools==82.0.0.20260210",
|
|
64
64
|
"xkcdpass==1.30.0",
|
|
65
65
|
]
|
|
66
66
|
docs = ["mkdocs", "mkdocs-material"]
|
|
@@ -74,9 +74,9 @@ exclude = ["tests*"]
|
|
|
74
74
|
|
|
75
75
|
[tool.pytest.ini_options]
|
|
76
76
|
filterwarnings = ["ignore::DeprecationWarning"]
|
|
77
|
-
|
|
78
77
|
markers = [
|
|
79
78
|
"requires_license: marks tests which require GitLab paid (Premium/Ultimate) license '-m \"not requires_license\"')",
|
|
79
|
+
"ce: marks tests which need to be run against GitLab CE image as well as the standard EE image"
|
|
80
80
|
]
|
|
81
81
|
|
|
82
82
|
#uncomment below for debug logging ALWAYS, even if the tests are passing
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
from logging import debug
|
|
2
|
-
from cli_ui import debug as verbose
|
|
3
|
-
|
|
4
|
-
import abc
|
|
5
|
-
from typing import Callable, Optional
|
|
6
|
-
|
|
7
|
-
from gitlabform.gitlab import GitLab
|
|
8
|
-
from gitlabform.processors.abstract_processor import AbstractProcessor
|
|
9
|
-
from gitlabform.processors.util.difference_logger import DifferenceLogger
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def noop():
|
|
13
|
-
pass
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class SingleEntityProcessor(AbstractProcessor, metaclass=abc.ABCMeta):
|
|
17
|
-
def __init__(
|
|
18
|
-
self,
|
|
19
|
-
configuration_name: str,
|
|
20
|
-
gitlab: GitLab,
|
|
21
|
-
get_method_name: str,
|
|
22
|
-
edit_method_name: str,
|
|
23
|
-
add_method_name: Optional[str] = None,
|
|
24
|
-
):
|
|
25
|
-
super().__init__(configuration_name, gitlab)
|
|
26
|
-
self.get_method: Callable = getattr(self.gitlab, get_method_name)
|
|
27
|
-
self.edit_method: Callable = getattr(self.gitlab, edit_method_name)
|
|
28
|
-
if add_method_name:
|
|
29
|
-
self.add_method: Callable = getattr(self.gitlab, add_method_name)
|
|
30
|
-
else:
|
|
31
|
-
self.add_method = noop
|
|
32
|
-
|
|
33
|
-
def _process_configuration(self, project_or_group: str, configuration: dict):
|
|
34
|
-
entity_config = configuration[self.configuration_name]
|
|
35
|
-
|
|
36
|
-
entity_in_gitlab = self.get_method(project_or_group)
|
|
37
|
-
debug(f"{self.configuration_name} BEFORE: ^^^")
|
|
38
|
-
|
|
39
|
-
if entity_in_gitlab:
|
|
40
|
-
if self._needs_update(entity_in_gitlab, entity_config):
|
|
41
|
-
verbose(f"Editing {self.configuration_name} in {project_or_group}")
|
|
42
|
-
self.edit_method(project_or_group, entity_config)
|
|
43
|
-
debug(f"{self.configuration_name} AFTER: ^^^")
|
|
44
|
-
else:
|
|
45
|
-
verbose(f"{self.configuration_name} in {project_or_group} doesn't need an update.")
|
|
46
|
-
else:
|
|
47
|
-
verbose(f"Adding {self.configuration_name} in {project_or_group}")
|
|
48
|
-
self.add_method(project_or_group, entity_config)
|
|
49
|
-
debug(f"{self.configuration_name} AFTER: ^^^")
|
|
50
|
-
|
|
51
|
-
def _print_diff(self, project_or_project_and_group: str, entity_config, diff_only_changed: bool):
|
|
52
|
-
entity_in_gitlab = self.get_method(project_or_project_and_group)
|
|
53
|
-
|
|
54
|
-
DifferenceLogger.log_diff(
|
|
55
|
-
f"{self.configuration_name} changes",
|
|
56
|
-
entity_in_gitlab,
|
|
57
|
-
entity_config,
|
|
58
|
-
only_changed=diff_only_changed,
|
|
59
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/project_merge_requests_approvals.py
RENAMED
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/gitlab/project_protected_environments.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_badges_processor.py
RENAMED
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_hooks_processor.py
RENAMED
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_labels_processor.py
RENAMED
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_ldap_links_processor.py
RENAMED
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_members_processor.py
RENAMED
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_push_rules_processor.py
RENAMED
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_saml_links_processor.py
RENAMED
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_settings_processor.py
RENAMED
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/group/group_variables_processor.py
RENAMED
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/multiple_entities_processor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/deploy_keys_processor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/integrations_processor.py
RENAMED
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/job_token_scope_processor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/merge_requests_approvals.py
RENAMED
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/project_labels_processor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/project_security_settings.py
RENAMED
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/project_settings_processor.py
RENAMED
|
File without changes
|
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/remote_mirrors_processor.py
RENAMED
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/resource_groups_processor.py
RENAMED
|
File without changes
|
{gitlabform-5.0.0rc1 → gitlabform-5.0.2}/gitlabform/processors/project/schedules_processor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|