gitlabform 3.9.0__tar.gz → 3.9.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-3.9.0 → gitlabform-3.9.2}/PKG-INFO +9 -9
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/lists/projects.py +109 -37
- gitlabform-3.9.2/gitlabform/processors/project/hooks_processor.py +70 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform.egg-info/PKG-INFO +9 -9
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform.egg-info/requires.txt +8 -8
- {gitlabform-3.9.0 → gitlabform-3.9.2}/setup.py +8 -8
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/conftest.py +23 -0
- gitlabform-3.9.2/tests/acceptance/standard/test_hooks.py +266 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_transfer_project.py +107 -0
- gitlabform-3.9.0/gitlabform/processors/project/hooks_processor.py +0 -66
- gitlabform-3.9.0/tests/acceptance/standard/test_hooks.py +0 -188
- {gitlabform-3.9.0 → gitlabform-3.9.2}/LICENSE +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/README.md +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/__init__.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/configuration/__init__.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/configuration/common.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/configuration/core.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/configuration/groups.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/configuration/projects.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/configuration/transform.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/constants.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/__init__.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/branches.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/commits.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/core.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/group_badges.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/group_ldap_links.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/group_variables.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/groups.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/integrations.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/members.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/merge_requests.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/pipelines.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/project_badges.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/project_deploy_keys.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/project_merge_requests_approvals.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/project_protected_environments.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/projects.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/repositories.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/resource_groups.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/schedules.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/users.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/gitlab/variables.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/lists/__init__.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/lists/filter.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/lists/groups.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/output.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/__init__.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/abstract_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/defining_keys.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/group/__init__.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/group/group_badges_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/group/group_ldap_links_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/group/group_members_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/group/group_settings_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/group/group_variables_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/multiple_entities_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/__init__.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/badges_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/branches_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/deploy_keys_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/files_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/integrations_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/members_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/merge_requests_approval_rules.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/merge_requests_approvals.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/project_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/project_push_rules_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/project_settings_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/resource_groups_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/schedules_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/tags_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/project/variables_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/shared/__init__.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/shared/protected_environments_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/single_entity_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/util/__init__.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/util/branch_protector.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/util/decorators.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/processors/util/difference_logger.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/run.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform/util.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform.egg-info/SOURCES.txt +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform.egg-info/dependency_links.txt +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform.egg-info/entry_points.txt +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/gitlabform.egg-info/top_level.txt +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/setup.cfg +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/__init__.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/__init__.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/__init__.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_archive_project.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_badges.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_branches.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_deploy_keys.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_deploy_keys_all_projects.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_files.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_files_all.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_files_protected.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_files_templates.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_group_badges.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_group_members_case_insensitive.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_group_members_groups.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_group_members_users.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_group_settings.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_group_variables.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_inheritance_break.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_integrations.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_members.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_members_add_group.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_members_enforce.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_project_group_members_case_insensitive.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_project_members_case_insensitve.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_project_settings.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_resource_groups.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_running.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_schedules.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_tags.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_token_from_config.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/acceptance/standard/test_variables.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/__init__.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/configuration/__init__.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/configuration/test_case_sensitivity.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/configuration/test_inheritance_break_projects_and_groups.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/configuration/test_inheritance_break_subgroups.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/configuration/test_inheritance_break_validation.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/configuration/test_projects_and_groups.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/configuration/test_skip_groups_skip_projects.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/configuration/test_subgroups.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/configuration/test_yaml_version.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/processors/__init__.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/processors/test_abstract_processor.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/processors/test_branch_protector.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/processors/test_difference_logger.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/test_access_levels.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/test_non_empty_configs_provider.py +0 -0
- {gitlabform-3.9.0 → gitlabform-3.9.2}/tests/unit/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: gitlabform
|
|
3
|
-
Version: 3.9.
|
|
3
|
+
Version: 3.9.2
|
|
4
4
|
Summary: 🏗 Specialized configuration as a code tool for GitLab projects, groups and more using hierarchical configuration written in YAML
|
|
5
5
|
Home-page: https://gitlabform.github.io/gitlabform
|
|
6
6
|
Author: Greg Dubicki and Contributors
|
|
@@ -28,22 +28,22 @@ Requires-Dist: Jinja2==3.1.3
|
|
|
28
28
|
Requires-Dist: luddite==1.0.2
|
|
29
29
|
Requires-Dist: MarkupSafe==2.1.5
|
|
30
30
|
Requires-Dist: mergedeep==1.3.4
|
|
31
|
-
Requires-Dist: packaging==
|
|
31
|
+
Requires-Dist: packaging==24.0
|
|
32
32
|
Requires-Dist: python-gitlab==4.4.0
|
|
33
33
|
Requires-Dist: requests==2.31.0
|
|
34
34
|
Requires-Dist: ruamel.yaml==0.17.21
|
|
35
|
-
Requires-Dist: types-requests==2.31.0.
|
|
35
|
+
Requires-Dist: types-requests==2.31.0.20240311
|
|
36
36
|
Requires-Dist: yamlpath==3.8.2
|
|
37
37
|
Provides-Extra: test
|
|
38
|
-
Requires-Dist: coverage==7.4.
|
|
39
|
-
Requires-Dist: cryptography==42.0.
|
|
38
|
+
Requires-Dist: coverage==7.4.4; extra == "test"
|
|
39
|
+
Requires-Dist: cryptography==42.0.5; extra == "test"
|
|
40
40
|
Requires-Dist: deepdiff==6.7.1; extra == "test"
|
|
41
|
-
Requires-Dist: mypy==1.
|
|
41
|
+
Requires-Dist: mypy==1.9.0; extra == "test"
|
|
42
42
|
Requires-Dist: mypy-extensions==1.0.0; extra == "test"
|
|
43
43
|
Requires-Dist: pre-commit==2.21.0; extra == "test"
|
|
44
|
-
Requires-Dist: pytest==
|
|
45
|
-
Requires-Dist: pytest-cov==
|
|
46
|
-
Requires-Dist: pytest-rerunfailures==
|
|
44
|
+
Requires-Dist: pytest==8.1.1; extra == "test"
|
|
45
|
+
Requires-Dist: pytest-cov==5.0.0; extra == "test"
|
|
46
|
+
Requires-Dist: pytest-rerunfailures==14.0; extra == "test"
|
|
47
47
|
Requires-Dist: xkcdpass==1.19.8; extra == "test"
|
|
48
48
|
Provides-Extra: docs
|
|
49
49
|
Requires-Dist: mkdocs; extra == "docs"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Tuple
|
|
1
|
+
from typing import Optional, Tuple
|
|
2
2
|
from logging import debug
|
|
3
3
|
from cli_ui import fatal
|
|
4
4
|
|
|
@@ -50,27 +50,19 @@ class ProjectsProvider(GroupsProvider):
|
|
|
50
50
|
|
|
51
51
|
except NotFoundException:
|
|
52
52
|
debug("Could not find '%s'", target)
|
|
53
|
-
|
|
54
|
-
"Checking if it's a project that needs to be transferred from elsewhere"
|
|
55
|
-
)
|
|
56
|
-
project_transfer_source = self.configuration.config["projects_and_groups"][
|
|
53
|
+
if project_transfer_source := self._get_project_transfer_source_from_config(
|
|
57
54
|
target
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
maybe_project = self.gitlab.get_project_case_insensitive(
|
|
63
|
-
project_transfer_source
|
|
64
|
-
)
|
|
65
|
-
debug(
|
|
66
|
-
"Found a project '%s' to be transferred to '%s'",
|
|
67
|
-
maybe_project["path_with_namespace"],
|
|
68
|
-
target,
|
|
69
|
-
)
|
|
55
|
+
):
|
|
56
|
+
if self._find_project_transfer_source_in_gitlab(
|
|
57
|
+
project_transfer_source
|
|
58
|
+
):
|
|
70
59
|
projects.add_requested([target])
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
60
|
+
else:
|
|
61
|
+
fatal(
|
|
62
|
+
f"""Configuration contains project {target} to be transferred from {project_transfer_source}
|
|
63
|
+
but the source project cannot be found in GitLab!""",
|
|
64
|
+
exit_code=EXIT_INVALID_INPUT,
|
|
65
|
+
)
|
|
74
66
|
|
|
75
67
|
return projects
|
|
76
68
|
|
|
@@ -85,21 +77,19 @@ class ProjectsProvider(GroupsProvider):
|
|
|
85
77
|
projects.add_requested(projects_from_groups)
|
|
86
78
|
projects.add_omitted(OmissionReason.ARCHIVED, archived_projects_from_groups)
|
|
87
79
|
|
|
88
|
-
|
|
89
|
-
# in this case we also need to get the list of projects explicitly
|
|
90
|
-
# defined in the configuration
|
|
91
|
-
|
|
92
|
-
projects_from_configuration = self.configuration.get_projects()
|
|
80
|
+
projects_from_configuration = self.configuration.get_projects()
|
|
93
81
|
|
|
94
|
-
|
|
95
|
-
|
|
82
|
+
# TODO: this check should be case-insensitive
|
|
83
|
+
projects_from_configuration_not_from_groups = [
|
|
84
|
+
project
|
|
85
|
+
for project in projects_from_configuration
|
|
86
|
+
if project not in projects.requested
|
|
87
|
+
]
|
|
96
88
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if project not in projects.requested
|
|
102
|
-
]
|
|
89
|
+
if target == "ALL_DEFINED":
|
|
90
|
+
# in this case we also need to get the list of projects explicitly
|
|
91
|
+
# defined in the configuration, but we don't need to re-check for
|
|
92
|
+
# being archived projects that we already got from groups
|
|
103
93
|
|
|
104
94
|
archived_projects_from_configuration_not_from_groups = (
|
|
105
95
|
self._verify_if_projects_exist_and_get_archived_projects(
|
|
@@ -112,6 +102,26 @@ class ProjectsProvider(GroupsProvider):
|
|
|
112
102
|
OmissionReason.ARCHIVED,
|
|
113
103
|
archived_projects_from_configuration_not_from_groups,
|
|
114
104
|
)
|
|
105
|
+
else:
|
|
106
|
+
# in all other cases, we also need to look for projects in the config
|
|
107
|
+
# that are being transferred to a different namespace
|
|
108
|
+
for project in projects_from_configuration_not_from_groups:
|
|
109
|
+
# if the target is a group, and the project is not in the group
|
|
110
|
+
if (
|
|
111
|
+
len(groups.get_effective()) == 1
|
|
112
|
+
and target != "ALL"
|
|
113
|
+
and target != project.rsplit("/", 1)[0]
|
|
114
|
+
):
|
|
115
|
+
debug(
|
|
116
|
+
"Ignore project '%s', since it's not in target group '%s",
|
|
117
|
+
project,
|
|
118
|
+
target,
|
|
119
|
+
)
|
|
120
|
+
else:
|
|
121
|
+
if (maybe_projects := self._get_single_project(project)) and len(
|
|
122
|
+
maybe_projects.get_effective()
|
|
123
|
+
) != 0:
|
|
124
|
+
projects.add_requested([project])
|
|
115
125
|
|
|
116
126
|
# TODO: consider checking for skipped earlier to avoid making requests for projects that will be skipped anyway
|
|
117
127
|
projects.add_omitted(
|
|
@@ -130,10 +140,28 @@ class ProjectsProvider(GroupsProvider):
|
|
|
130
140
|
if project_object["archived"]:
|
|
131
141
|
archived.append(project_object["path_with_namespace"])
|
|
132
142
|
except NotFoundException:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
)
|
|
143
|
+
debug("Could not find '%s'", project)
|
|
144
|
+
if project_transfer_source := self._get_project_transfer_source_from_config(
|
|
145
|
+
project
|
|
146
|
+
):
|
|
147
|
+
source_project = self._find_project_transfer_source_in_gitlab(
|
|
148
|
+
project_transfer_source
|
|
149
|
+
)
|
|
150
|
+
if source_project:
|
|
151
|
+
if source_project["archived"]:
|
|
152
|
+
archived.append(project)
|
|
153
|
+
else:
|
|
154
|
+
fatal(
|
|
155
|
+
f"""Configuration contains project {project} to be transferred from {project_transfer_source}
|
|
156
|
+
but the source project cannot be found in GitLab!""",
|
|
157
|
+
exit_code=EXIT_INVALID_INPUT,
|
|
158
|
+
)
|
|
159
|
+
else:
|
|
160
|
+
fatal(
|
|
161
|
+
f"Configuration contains project {project} but it cannot be found in GitLab and it's not a project that is configured to be transferred from elsewhere.",
|
|
162
|
+
exit_code=EXIT_INVALID_INPUT,
|
|
163
|
+
)
|
|
164
|
+
|
|
137
165
|
return archived
|
|
138
166
|
|
|
139
167
|
def _get_all_and_archived_projects_from_groups(
|
|
@@ -165,3 +193,47 @@ class ProjectsProvider(GroupsProvider):
|
|
|
165
193
|
skipped.append(project)
|
|
166
194
|
|
|
167
195
|
return skipped
|
|
196
|
+
|
|
197
|
+
def _get_project_transfer_source_from_config(self, project: str) -> Optional[str]:
|
|
198
|
+
try:
|
|
199
|
+
debug(
|
|
200
|
+
"Checking if project '%s' needs to be transferred from elsewhere",
|
|
201
|
+
project,
|
|
202
|
+
)
|
|
203
|
+
project_transfer_source = self.configuration.config["projects_and_groups"][
|
|
204
|
+
project
|
|
205
|
+
]["project"]["transfer_from"]
|
|
206
|
+
debug(
|
|
207
|
+
"Project '%s' needs to be transferred from '%s'",
|
|
208
|
+
project,
|
|
209
|
+
project_transfer_source,
|
|
210
|
+
)
|
|
211
|
+
except KeyError:
|
|
212
|
+
debug("'%s' is not a project needing to be transferred", project)
|
|
213
|
+
return None
|
|
214
|
+
|
|
215
|
+
return project_transfer_source
|
|
216
|
+
|
|
217
|
+
def _find_project_transfer_source_in_gitlab(
|
|
218
|
+
self, project_transfer_source: str
|
|
219
|
+
) -> Optional[dict]:
|
|
220
|
+
try:
|
|
221
|
+
debug(
|
|
222
|
+
"Checking if project transfer source ('%s') exists in GitLab",
|
|
223
|
+
project_transfer_source,
|
|
224
|
+
)
|
|
225
|
+
maybe_project = self.gitlab.get_project_case_insensitive(
|
|
226
|
+
project_transfer_source
|
|
227
|
+
)
|
|
228
|
+
debug(
|
|
229
|
+
"Project transfer source ('%s') exists",
|
|
230
|
+
project_transfer_source,
|
|
231
|
+
)
|
|
232
|
+
except NotFoundException:
|
|
233
|
+
debug(
|
|
234
|
+
"Project transfer source ('%s') does not exist",
|
|
235
|
+
project_transfer_source,
|
|
236
|
+
)
|
|
237
|
+
return None
|
|
238
|
+
|
|
239
|
+
return maybe_project
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from logging import debug
|
|
2
|
+
from typing import Dict, Any, List
|
|
3
|
+
|
|
4
|
+
from gitlab.base import RESTObject, RESTObjectList
|
|
5
|
+
from gitlab.v4.objects import Project
|
|
6
|
+
|
|
7
|
+
from gitlabform.gitlab import GitLab
|
|
8
|
+
from gitlabform.processors.abstract_processor import AbstractProcessor
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class HooksProcessor(AbstractProcessor):
|
|
12
|
+
def __init__(self, gitlab: GitLab):
|
|
13
|
+
super().__init__("hooks", gitlab)
|
|
14
|
+
|
|
15
|
+
def _process_configuration(self, project_and_group: str, configuration: dict):
|
|
16
|
+
debug("Processing hooks...")
|
|
17
|
+
project: Project = self.gl.projects.get(project_and_group)
|
|
18
|
+
project_hooks: RESTObjectList | List[RESTObject] = project.hooks.list()
|
|
19
|
+
hooks_in_config: tuple[str, ...] = tuple(
|
|
20
|
+
x for x in sorted(configuration["hooks"]) if x != "enforce"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
for hook in hooks_in_config:
|
|
24
|
+
hook_in_gitlab: RESTObject | None = next(
|
|
25
|
+
(h for h in project_hooks if h.url == hook), None
|
|
26
|
+
)
|
|
27
|
+
hook_config = {"url": hook}
|
|
28
|
+
hook_config.update(configuration["hooks"][hook])
|
|
29
|
+
|
|
30
|
+
hook_id = hook_in_gitlab.id if hook_in_gitlab else None
|
|
31
|
+
|
|
32
|
+
# Process hooks configured for deletion
|
|
33
|
+
if configuration.get("hooks|" + hook + "|delete"):
|
|
34
|
+
if hook_id:
|
|
35
|
+
debug(f"Deleting hook '{hook}'")
|
|
36
|
+
project.hooks.delete(hook_id)
|
|
37
|
+
debug(f"Deleted hook '{hook}'")
|
|
38
|
+
else:
|
|
39
|
+
debug(f"Not deleting hook '{hook}', because it doesn't exist")
|
|
40
|
+
continue
|
|
41
|
+
|
|
42
|
+
# Process new hook creation
|
|
43
|
+
if not hook_id:
|
|
44
|
+
debug(f"Creating hook '{hook}'")
|
|
45
|
+
created_hook: RESTObject = project.hooks.create(hook_config)
|
|
46
|
+
debug(f"Created hook: {created_hook}")
|
|
47
|
+
continue
|
|
48
|
+
|
|
49
|
+
# Processing existing hook updates
|
|
50
|
+
gl_hook: dict = hook_in_gitlab.asdict() if hook_in_gitlab else {}
|
|
51
|
+
if self._needs_update(gl_hook, hook_config):
|
|
52
|
+
debug(
|
|
53
|
+
f"The hook '{hook}' config is different from what's in gitlab OR it contains a token"
|
|
54
|
+
)
|
|
55
|
+
debug(f"Updating hook '{hook}'")
|
|
56
|
+
updated_hook: Dict[str, Any] = project.hooks.update(
|
|
57
|
+
hook_id, hook_config
|
|
58
|
+
)
|
|
59
|
+
debug(f"Updated hook: {updated_hook}")
|
|
60
|
+
else:
|
|
61
|
+
debug(f"Hook '{hook}' remains unchanged")
|
|
62
|
+
|
|
63
|
+
# Process hook config enforcements
|
|
64
|
+
if configuration.get("hooks|enforce"):
|
|
65
|
+
for gh in project_hooks:
|
|
66
|
+
if gh.url not in hooks_in_config:
|
|
67
|
+
debug(
|
|
68
|
+
f"Deleting hook '{gh.url}' currently setup in the project but it is not in the configuration and enforce is enabled"
|
|
69
|
+
)
|
|
70
|
+
project.hooks.delete(gh.id)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: gitlabform
|
|
3
|
-
Version: 3.9.
|
|
3
|
+
Version: 3.9.2
|
|
4
4
|
Summary: 🏗 Specialized configuration as a code tool for GitLab projects, groups and more using hierarchical configuration written in YAML
|
|
5
5
|
Home-page: https://gitlabform.github.io/gitlabform
|
|
6
6
|
Author: Greg Dubicki and Contributors
|
|
@@ -28,22 +28,22 @@ Requires-Dist: Jinja2==3.1.3
|
|
|
28
28
|
Requires-Dist: luddite==1.0.2
|
|
29
29
|
Requires-Dist: MarkupSafe==2.1.5
|
|
30
30
|
Requires-Dist: mergedeep==1.3.4
|
|
31
|
-
Requires-Dist: packaging==
|
|
31
|
+
Requires-Dist: packaging==24.0
|
|
32
32
|
Requires-Dist: python-gitlab==4.4.0
|
|
33
33
|
Requires-Dist: requests==2.31.0
|
|
34
34
|
Requires-Dist: ruamel.yaml==0.17.21
|
|
35
|
-
Requires-Dist: types-requests==2.31.0.
|
|
35
|
+
Requires-Dist: types-requests==2.31.0.20240311
|
|
36
36
|
Requires-Dist: yamlpath==3.8.2
|
|
37
37
|
Provides-Extra: test
|
|
38
|
-
Requires-Dist: coverage==7.4.
|
|
39
|
-
Requires-Dist: cryptography==42.0.
|
|
38
|
+
Requires-Dist: coverage==7.4.4; extra == "test"
|
|
39
|
+
Requires-Dist: cryptography==42.0.5; extra == "test"
|
|
40
40
|
Requires-Dist: deepdiff==6.7.1; extra == "test"
|
|
41
|
-
Requires-Dist: mypy==1.
|
|
41
|
+
Requires-Dist: mypy==1.9.0; extra == "test"
|
|
42
42
|
Requires-Dist: mypy-extensions==1.0.0; extra == "test"
|
|
43
43
|
Requires-Dist: pre-commit==2.21.0; extra == "test"
|
|
44
|
-
Requires-Dist: pytest==
|
|
45
|
-
Requires-Dist: pytest-cov==
|
|
46
|
-
Requires-Dist: pytest-rerunfailures==
|
|
44
|
+
Requires-Dist: pytest==8.1.1; extra == "test"
|
|
45
|
+
Requires-Dist: pytest-cov==5.0.0; extra == "test"
|
|
46
|
+
Requires-Dist: pytest-rerunfailures==14.0; extra == "test"
|
|
47
47
|
Requires-Dist: xkcdpass==1.19.8; extra == "test"
|
|
48
48
|
Provides-Extra: docs
|
|
49
49
|
Requires-Dist: mkdocs; extra == "docs"
|
|
@@ -5,11 +5,11 @@ Jinja2==3.1.3
|
|
|
5
5
|
luddite==1.0.2
|
|
6
6
|
MarkupSafe==2.1.5
|
|
7
7
|
mergedeep==1.3.4
|
|
8
|
-
packaging==
|
|
8
|
+
packaging==24.0
|
|
9
9
|
python-gitlab==4.4.0
|
|
10
10
|
requests==2.31.0
|
|
11
11
|
ruamel.yaml==0.17.21
|
|
12
|
-
types-requests==2.31.0.
|
|
12
|
+
types-requests==2.31.0.20240311
|
|
13
13
|
yamlpath==3.8.2
|
|
14
14
|
|
|
15
15
|
[docs]
|
|
@@ -17,13 +17,13 @@ mkdocs
|
|
|
17
17
|
mkdocs-material
|
|
18
18
|
|
|
19
19
|
[test]
|
|
20
|
-
coverage==7.4.
|
|
21
|
-
cryptography==42.0.
|
|
20
|
+
coverage==7.4.4
|
|
21
|
+
cryptography==42.0.5
|
|
22
22
|
deepdiff==6.7.1
|
|
23
|
-
mypy==1.
|
|
23
|
+
mypy==1.9.0
|
|
24
24
|
mypy-extensions==1.0.0
|
|
25
25
|
pre-commit==2.21.0
|
|
26
|
-
pytest==
|
|
27
|
-
pytest-cov==
|
|
28
|
-
pytest-rerunfailures==
|
|
26
|
+
pytest==8.1.1
|
|
27
|
+
pytest-cov==5.0.0
|
|
28
|
+
pytest-rerunfailures==14.0
|
|
29
29
|
xkcdpass==1.19.8
|
|
@@ -51,24 +51,24 @@ setup(
|
|
|
51
51
|
"luddite==1.0.2",
|
|
52
52
|
"MarkupSafe==2.1.5",
|
|
53
53
|
"mergedeep==1.3.4",
|
|
54
|
-
"packaging==
|
|
54
|
+
"packaging==24.0",
|
|
55
55
|
"python-gitlab==4.4.0",
|
|
56
56
|
"requests==2.31.0",
|
|
57
57
|
"ruamel.yaml==0.17.21",
|
|
58
|
-
"types-requests==2.31.0.
|
|
58
|
+
"types-requests==2.31.0.20240311",
|
|
59
59
|
"yamlpath==3.8.2",
|
|
60
60
|
],
|
|
61
61
|
extras_require={
|
|
62
62
|
"test": [
|
|
63
|
-
"coverage==7.4.
|
|
64
|
-
"cryptography==42.0.
|
|
63
|
+
"coverage==7.4.4",
|
|
64
|
+
"cryptography==42.0.5",
|
|
65
65
|
"deepdiff==6.7.1",
|
|
66
|
-
"mypy==1.
|
|
66
|
+
"mypy==1.9.0",
|
|
67
67
|
"mypy-extensions==1.0.0",
|
|
68
68
|
"pre-commit==2.21.0", # not really for tests, but for development
|
|
69
|
-
"pytest==
|
|
70
|
-
"pytest-cov==
|
|
71
|
-
"pytest-rerunfailures==
|
|
69
|
+
"pytest==8.1.1",
|
|
70
|
+
"pytest-cov==5.0.0",
|
|
71
|
+
"pytest-rerunfailures==14.0",
|
|
72
72
|
"xkcdpass==1.19.8",
|
|
73
73
|
],
|
|
74
74
|
"docs": [
|
|
@@ -99,6 +99,18 @@ def subgroup(gl: Gitlab, group: Group):
|
|
|
99
99
|
gl.groups.delete(f"{group.full_path}/{subgroup_name}")
|
|
100
100
|
|
|
101
101
|
|
|
102
|
+
@pytest.fixture(scope="class")
|
|
103
|
+
def other_subgroup(gl: Gitlab, group: Group):
|
|
104
|
+
# TODO: deduplicate this - it's a copy and paste from the above fixture
|
|
105
|
+
subgroup_name = get_random_name("subgroup")
|
|
106
|
+
gitlab_subgroup = create_group(subgroup_name, group.id)
|
|
107
|
+
|
|
108
|
+
yield gitlab_subgroup
|
|
109
|
+
|
|
110
|
+
with allowed_codes(404):
|
|
111
|
+
gl.groups.delete(f"{group.full_path}/{subgroup_name}")
|
|
112
|
+
|
|
113
|
+
|
|
102
114
|
@pytest.fixture(scope="class")
|
|
103
115
|
def project(gl: Gitlab, group: Group):
|
|
104
116
|
project_name = get_random_name("project")
|
|
@@ -119,6 +131,17 @@ def project_in_subgroup(gl: Gitlab, subgroup: Group):
|
|
|
119
131
|
gitlab_project.delete()
|
|
120
132
|
|
|
121
133
|
|
|
134
|
+
@pytest.fixture(scope="class")
|
|
135
|
+
def project_in_other_subgroup(gl: Gitlab, other_subgroup: Group):
|
|
136
|
+
# TODO: deduplicate this - it's a copy and paste from the above fixture
|
|
137
|
+
project_name = get_random_name("project")
|
|
138
|
+
gitlab_project = create_project(other_subgroup, project_name)
|
|
139
|
+
|
|
140
|
+
yield gitlab_project
|
|
141
|
+
|
|
142
|
+
gitlab_project.delete()
|
|
143
|
+
|
|
144
|
+
|
|
122
145
|
@pytest.fixture(scope="function")
|
|
123
146
|
def project_for_function(gl: Gitlab, group: Group):
|
|
124
147
|
project_name = get_random_name("project")
|