gitlabform 0.0.540a0__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 (79) hide show
  1. gitlabform/__init__.py +719 -0
  2. gitlabform/configuration/__init__.py +12 -0
  3. gitlabform/configuration/common.py +19 -0
  4. gitlabform/configuration/core.py +323 -0
  5. gitlabform/configuration/groups.py +127 -0
  6. gitlabform/configuration/projects.py +73 -0
  7. gitlabform/configuration/transform.py +259 -0
  8. gitlabform/constants.py +7 -0
  9. gitlabform/gitlab/__init__.py +108 -0
  10. gitlabform/gitlab/commits.py +39 -0
  11. gitlabform/gitlab/core.py +334 -0
  12. gitlabform/gitlab/group_badges.py +50 -0
  13. gitlabform/gitlab/group_ldap_links.py +40 -0
  14. gitlabform/gitlab/groups.py +96 -0
  15. gitlabform/gitlab/merge_requests.py +57 -0
  16. gitlabform/gitlab/pipelines.py +23 -0
  17. gitlabform/gitlab/project_badges.py +52 -0
  18. gitlabform/gitlab/project_deploy_keys.py +102 -0
  19. gitlabform/gitlab/project_merge_requests_approvals.py +94 -0
  20. gitlabform/gitlab/project_protected_environments.py +37 -0
  21. gitlabform/gitlab/projects.py +151 -0
  22. gitlabform/gitlab/python_gitlab.py +251 -0
  23. gitlabform/gitlab/variables.py +47 -0
  24. gitlabform/lists/__init__.py +62 -0
  25. gitlabform/lists/filter.py +99 -0
  26. gitlabform/lists/groups.py +87 -0
  27. gitlabform/lists/projects.py +239 -0
  28. gitlabform/output.py +46 -0
  29. gitlabform/processors/__init__.py +43 -0
  30. gitlabform/processors/abstract_processor.py +187 -0
  31. gitlabform/processors/application/__init__.py +17 -0
  32. gitlabform/processors/application/application_settings_processor.py +39 -0
  33. gitlabform/processors/defining_keys.py +152 -0
  34. gitlabform/processors/group/__init__.py +48 -0
  35. gitlabform/processors/group/group_badges_processor.py +17 -0
  36. gitlabform/processors/group/group_hooks_processor.py +75 -0
  37. gitlabform/processors/group/group_labels_processor.py +28 -0
  38. gitlabform/processors/group/group_ldap_links_processor.py +16 -0
  39. gitlabform/processors/group/group_members_processor.py +287 -0
  40. gitlabform/processors/group/group_push_rules_processor.py +44 -0
  41. gitlabform/processors/group/group_saml_links_processor.py +65 -0
  42. gitlabform/processors/group/group_settings_processor.py +90 -0
  43. gitlabform/processors/group/group_variables_processor.py +26 -0
  44. gitlabform/processors/multiple_entities_processor.py +171 -0
  45. gitlabform/processors/project/__init__.py +80 -0
  46. gitlabform/processors/project/badges_processor.py +17 -0
  47. gitlabform/processors/project/branches_processor.py +514 -0
  48. gitlabform/processors/project/deploy_keys_processor.py +18 -0
  49. gitlabform/processors/project/files_processor.py +301 -0
  50. gitlabform/processors/project/hooks_processor.py +64 -0
  51. gitlabform/processors/project/integrations_processor.py +33 -0
  52. gitlabform/processors/project/job_token_scope_processor.py +216 -0
  53. gitlabform/processors/project/members_processor.py +204 -0
  54. gitlabform/processors/project/merge_requests_approval_rules.py +17 -0
  55. gitlabform/processors/project/merge_requests_approvals.py +59 -0
  56. gitlabform/processors/project/project_labels_processor.py +27 -0
  57. gitlabform/processors/project/project_processor.py +62 -0
  58. gitlabform/processors/project/project_push_rules_processor.py +52 -0
  59. gitlabform/processors/project/project_security_settings.py +66 -0
  60. gitlabform/processors/project/project_settings_processor.py +239 -0
  61. gitlabform/processors/project/project_variables_processor.py +94 -0
  62. gitlabform/processors/project/remote_mirrors_processor.py +278 -0
  63. gitlabform/processors/project/resource_groups_processor.py +48 -0
  64. gitlabform/processors/project/schedules_processor.py +208 -0
  65. gitlabform/processors/project/tags_processor.py +108 -0
  66. gitlabform/processors/shared/__init__.py +0 -0
  67. gitlabform/processors/shared/protected_environments_processor.py +20 -0
  68. gitlabform/processors/util/__init__.py +0 -0
  69. gitlabform/processors/util/decorators.py +44 -0
  70. gitlabform/processors/util/difference_logger.py +70 -0
  71. gitlabform/processors/util/labels_processor.py +120 -0
  72. gitlabform/processors/util/variables_processor.py +143 -0
  73. gitlabform/run.py +9 -0
  74. gitlabform/util.py +7 -0
  75. gitlabform-0.0.540a0.dist-info/METADATA +54 -0
  76. gitlabform-0.0.540a0.dist-info/RECORD +79 -0
  77. gitlabform-0.0.540a0.dist-info/WHEEL +4 -0
  78. gitlabform-0.0.540a0.dist-info/entry_points.txt +9 -0
  79. gitlabform-0.0.540a0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,171 @@
1
+ import sys
2
+ from logging import debug, info, critical
3
+
4
+ import abc
5
+ from typing import Callable, Union, Any
6
+ from gitlabform.constants import EXIT_INVALID_INPUT
7
+ from gitlabform.gitlab import GitLab
8
+ from gitlabform.processors.abstract_processor import AbstractProcessor
9
+ from gitlabform.processors.defining_keys import AbstractKey
10
+
11
+
12
+ class MultipleEntitiesProcessor(AbstractProcessor, metaclass=abc.ABCMeta):
13
+ def __init__(
14
+ self,
15
+ configuration_name: str,
16
+ gitlab: GitLab,
17
+ list_method_name: Union[str, Callable[[str], list]],
18
+ add_method_name: Union[str, Callable[[str, Any], None]],
19
+ delete_method_name: Union[str, Callable[[str, dict], None]],
20
+ defining: AbstractKey,
21
+ required_to_create_or_update: AbstractKey,
22
+ edit_method_name: Union[str, Callable[[str, dict, dict], None], None] = None,
23
+ ):
24
+ """
25
+ :param configuration_name: The key in the YAML cfg file that determines the start of this Entity's section
26
+ :param gitlab: Gitlab instance
27
+ :param list_method_name: Retrieves the entities in question
28
+ :param add_method_name: Creates a new entity in Gitlab
29
+ :param delete_method_name: Removes the entity from Gitlab
30
+ :param defining: An expression that tells which fields of the entity in GitLab are identifying it.
31
+ :param required_to_create_or_update: Entries which (according to the API documentation) are required fields
32
+ :param edit_method_name: Edits the existing entity in Gitlab
33
+ """
34
+
35
+ super().__init__(configuration_name, gitlab)
36
+ self.list_method: Callable = (
37
+ getattr(self.gitlab, list_method_name) if (isinstance(list_method_name, str)) else list_method_name
38
+ )
39
+ self.add_method: Callable = (
40
+ getattr(self.gitlab, add_method_name) if (isinstance(add_method_name, str)) else add_method_name
41
+ )
42
+ self.delete_method: Callable = (
43
+ getattr(self.gitlab, delete_method_name) if (isinstance(delete_method_name, str)) else delete_method_name
44
+ )
45
+ self.defining: AbstractKey = defining
46
+ self.required_to_create_or_update: AbstractKey = required_to_create_or_update
47
+
48
+ if edit_method_name:
49
+ self.edit_method: Union[Callable, None] = (
50
+ getattr(self.gitlab, edit_method_name) if (isinstance(edit_method_name, str)) else edit_method_name
51
+ )
52
+ else:
53
+ self.edit_method = None
54
+
55
+ def _process_configuration(self, project_or_group: str, configuration: dict):
56
+ entities_in_configuration = configuration[self.configuration_name]
57
+ if "enforce" in entities_in_configuration:
58
+ enforce = entities_in_configuration["enforce"]
59
+ del entities_in_configuration["enforce"]
60
+ else:
61
+ enforce = False
62
+
63
+ # TODO: move/convert this to a configuration validation phase
64
+ self._find_duplicates(project_or_group, entities_in_configuration)
65
+
66
+ entities_in_gitlab = {}
67
+ i = 1
68
+ for entity_in_gitlab in self.list_method(project_or_group):
69
+ entities_in_gitlab[str(i)] = entity_in_gitlab
70
+ i += 1
71
+
72
+ debug(f"{self.configuration_name} BEFORE: ^^^")
73
+
74
+ # group entities into 3 groups:
75
+ # a) only in gitlab,
76
+ # b) in both configuration and gitlab (matching defining keys),
77
+ # c) only in configuration,
78
+
79
+ entities_only_in_gitlab = {
80
+ entity_name: entity_config
81
+ for (entity_name, entity_config) in entities_in_gitlab.items()
82
+ if not self._is_in(entity_config, entities_in_configuration)
83
+ }
84
+
85
+ entities_in_both = {
86
+ entity_name: entity_config
87
+ for (entity_name, entity_config) in entities_in_configuration.items()
88
+ if self._is_in(entity_config, entities_in_gitlab)
89
+ }
90
+
91
+ entities_only_in_configuration = {
92
+ entity_name: entity_config
93
+ for (entity_name, entity_config) in entities_in_configuration.items()
94
+ if not self._is_in(entity_config, entities_in_gitlab)
95
+ }
96
+
97
+ # if "enforce", then delete a)
98
+
99
+ if enforce:
100
+ for entity_name, entity_config in entities_only_in_gitlab.items():
101
+ # no need to validate if we have what's needed to delete as we got the entities from gitlab
102
+ info(
103
+ f"Deleting entity no {entity_name} of {self.configuration_name} in {project_or_group} "
104
+ f"as it's not in config and enforce is set to true."
105
+ )
106
+ self.delete_method(project_or_group, entity_config)
107
+
108
+ # update b), if needed (or delete them if marked as "delete")
109
+
110
+ for entity_name, entity_config in entities_in_both.items():
111
+ entity_in_gitlab = self._is_in(entity_config, entities_in_gitlab)
112
+ if entity_config.get("delete", False):
113
+ self._validate_required_to_delete(project_or_group, entity_name, entity_config)
114
+ info(f"Deleting {entity_name} of {self.configuration_name} in {project_or_group}")
115
+ self.delete_method(project_or_group, entity_in_gitlab)
116
+ elif self._needs_update(entity_in_gitlab, entity_config):
117
+ self._validate_required_to_create_or_update(project_or_group, entity_name, entity_config)
118
+ if self.edit_method:
119
+ info(f"Editing {entity_name} of {self.configuration_name} in {project_or_group}")
120
+ self.edit_method(project_or_group, entity_in_gitlab, entity_config)
121
+ debug(f"{self.configuration_name} AFTER: ^^^")
122
+ else:
123
+ info(f" * Recreating {entity_name} of {self.configuration_name} in {project_or_group}")
124
+ self.delete_method(project_or_group, entity_in_gitlab)
125
+ self.add_method(project_or_group, entity_config)
126
+ debug(f"{self.configuration_name} AFTER: ^^^")
127
+ else:
128
+ info(f" * {entity_name} of {self.configuration_name} in {project_or_group} doesn't need an update.")
129
+
130
+ # add c) (or do nothing if marked as "delete")
131
+
132
+ for entity_name, entity_config in entities_only_in_configuration.items():
133
+ self._validate_required_to_create_or_update(project_or_group, entity_name, entity_config)
134
+ info(f" * Adding {entity_name} of {self.configuration_name} in {project_or_group}")
135
+ self.add_method(project_or_group, entity_config)
136
+ debug(f"{self.configuration_name} AFTER: ^^^")
137
+
138
+ def _find_duplicates(self, project_or_group: str, entities_in_configuration: dict):
139
+ for first_key, first_value in entities_in_configuration.items():
140
+ for second_key, second_value in entities_in_configuration.items():
141
+ if first_key != second_key:
142
+ if self.defining.matches(first_value, second_value):
143
+ critical(
144
+ f"Entities {first_key} and {second_key} in {self.configuration_name} for {project_or_group}"
145
+ f" are the same in terms of their defining keys: {self.defining.explain()}"
146
+ )
147
+ sys.exit(EXIT_INVALID_INPUT)
148
+
149
+ def _validate_required_to_create_or_update(self, project_or_group: str, entity_name: str, entity_dict: dict):
150
+ if not self.required_to_create_or_update.contains(entity_dict):
151
+ critical(
152
+ f"Entity {entity_name} in {self.configuration_name} for {project_or_group}"
153
+ f" doesn't have some of its keys required to create or update:"
154
+ f" {self.required_to_create_or_update.explain()}"
155
+ )
156
+ sys.exit(EXIT_INVALID_INPUT)
157
+
158
+ def _validate_required_to_delete(self, project_or_group: str, entity_name: str, entity_dict: dict):
159
+ if not self.defining.contains(entity_dict):
160
+ critical(
161
+ f"Entity {entity_name} in {self.configuration_name} for {project_or_group}"
162
+ f" doesn't have some of its defining keys required to delete it: {self.defining.explain()}"
163
+ )
164
+ sys.exit(EXIT_INVALID_INPUT)
165
+
166
+ def _is_in(self, entity: dict, dict_of_entities: dict):
167
+ for entity_name, entity_config in dict_of_entities.items():
168
+ if self.defining.matches(entity, entity_config):
169
+ return entity_config
170
+
171
+ return False
@@ -0,0 +1,80 @@
1
+ from typing import List
2
+
3
+ from gitlabform.configuration import Configuration
4
+ from gitlabform.gitlab import GitLab
5
+ from gitlabform.processors import AbstractProcessors
6
+ from gitlabform.processors.abstract_processor import AbstractProcessor
7
+ from gitlabform.processors.project.badges_processor import BadgesProcessor
8
+ from gitlabform.processors.project.branches_processor import BranchesProcessor
9
+ from gitlabform.processors.project.deploy_keys_processor import DeployKeysProcessor
10
+ from gitlabform.processors.project.files_processor import FilesProcessor
11
+ from gitlabform.processors.project.hooks_processor import HooksProcessor
12
+ from gitlabform.processors.project.integrations_processor import IntegrationsProcessor
13
+ from gitlabform.processors.project.job_token_scope_processor import (
14
+ JobTokenScopeProcessor,
15
+ )
16
+ from gitlabform.processors.project.members_processor import MembersProcessor
17
+ from gitlabform.processors.project.merge_requests_approval_rules import (
18
+ MergeRequestsApprovalRules,
19
+ )
20
+ from gitlabform.processors.project.merge_requests_approvals import (
21
+ MergeRequestsApprovals,
22
+ )
23
+ from gitlabform.processors.project.project_labels_processor import (
24
+ ProjectLabelsProcessor,
25
+ )
26
+ from gitlabform.processors.project.project_processor import ProjectProcessor
27
+ from gitlabform.processors.project.project_push_rules_processor import (
28
+ ProjectPushRulesProcessor,
29
+ )
30
+ from gitlabform.processors.project.project_settings_processor import (
31
+ ProjectSettingsProcessor,
32
+ )
33
+ from gitlabform.processors.project.resource_groups_processor import (
34
+ ResourceGroupsProcessor,
35
+ )
36
+ from gitlabform.processors.project.schedules_processor import SchedulesProcessor
37
+ from gitlabform.processors.project.tags_processor import TagsProcessor
38
+ from gitlabform.processors.project.project_variables_processor import ProjectVariablesProcessor
39
+ from gitlabform.processors.shared.protected_environments_processor import (
40
+ ProtectedEnvironmentsProcessor,
41
+ )
42
+
43
+ from gitlabform.processors.project.project_security_settings import (
44
+ ProjectSecuritySettingsProcessor,
45
+ )
46
+ from gitlabform.processors.project.remote_mirrors_processor import RemoteMirrorsProcessor
47
+
48
+
49
+ class ProjectProcessors(AbstractProcessors):
50
+ def __init__(self, gitlab: GitLab, config: Configuration, strict: bool):
51
+ super().__init__(gitlab, config, strict)
52
+ self.processors: List[AbstractProcessor] = [
53
+ # Order of processors matter. GitLabForm will process config sections
54
+ # in the order listed below. Settings that are related to each other,
55
+ # should be ordered accordingly. For example, branch protection or MR
56
+ # approvals can configure specific users, but the user must be a
57
+ # member of the project. So, project membership must be processed
58
+ # before those processors.
59
+ ProjectProcessor(gitlab),
60
+ ProjectSettingsProcessor(gitlab, strict),
61
+ ProjectSecuritySettingsProcessor(gitlab),
62
+ MembersProcessor(gitlab),
63
+ ProjectPushRulesProcessor(gitlab),
64
+ ProjectLabelsProcessor(gitlab),
65
+ JobTokenScopeProcessor(gitlab),
66
+ DeployKeysProcessor(gitlab),
67
+ ProjectVariablesProcessor(gitlab),
68
+ BranchesProcessor(gitlab, strict),
69
+ TagsProcessor(gitlab, strict),
70
+ IntegrationsProcessor(gitlab),
71
+ FilesProcessor(gitlab, config, strict),
72
+ HooksProcessor(gitlab),
73
+ SchedulesProcessor(gitlab),
74
+ BadgesProcessor(gitlab),
75
+ ResourceGroupsProcessor(gitlab),
76
+ ProtectedEnvironmentsProcessor(gitlab),
77
+ MergeRequestsApprovals(gitlab),
78
+ MergeRequestsApprovalRules(gitlab),
79
+ RemoteMirrorsProcessor(gitlab),
80
+ ]
@@ -0,0 +1,17 @@
1
+ from gitlabform.gitlab import GitLab
2
+ from gitlabform.processors.defining_keys import Key, And
3
+ from gitlabform.processors.multiple_entities_processor import MultipleEntitiesProcessor
4
+
5
+
6
+ class BadgesProcessor(MultipleEntitiesProcessor):
7
+ def __init__(self, gitlab: GitLab):
8
+ super().__init__(
9
+ "badges",
10
+ gitlab,
11
+ list_method_name="get_project_badges",
12
+ add_method_name="add_project_badge",
13
+ delete_method_name="delete_project_badge",
14
+ defining=Key("name"),
15
+ required_to_create_or_update=And(Key("name"), Key("link_url"), Key("image_url")),
16
+ edit_method_name="edit_project_badge",
17
+ )