gitlab-projects-settings 2.0.2__tar.gz → 3.0.0__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.
Files changed (43) hide show
  1. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/.gitlab-ci.yml +37 -37
  2. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/CHANGELOG.md +43 -0
  3. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/PKG-INFO +12 -4
  4. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/README.md +11 -3
  5. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/gitlab_projects_settings.egg-info/PKG-INFO +12 -4
  6. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/gitlab_projects_settings.egg-info/SOURCES.txt +3 -1
  7. gitlab_projects_settings-3.0.0/src/cli/entrypoint.py +401 -0
  8. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/src/cli/main.py +38 -2
  9. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/src/features/gitlab.py +133 -37
  10. gitlab_projects_settings-3.0.0/src/types/__init__.py +0 -0
  11. gitlab_projects_settings-3.0.0/src/types/namespaces.py +33 -0
  12. gitlab_projects_settings-2.0.2/src/cli/entrypoint.py +0 -273
  13. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/.chglog/CHANGELOG.tpl.md +0 -0
  14. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/.chglog/changelog.sh +0 -0
  15. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/.chglog/config.yml +0 -0
  16. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/.gitignore +0 -0
  17. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/.markdownlint.json +0 -0
  18. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/.style.yapf +0 -0
  19. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/.vscode/extensions.json +0 -0
  20. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/.vscode/settings.json +0 -0
  21. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/LICENSE +0 -0
  22. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/gitlab_projects_settings.egg-info/dependency_links.txt +0 -0
  23. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/gitlab_projects_settings.egg-info/entry_points.txt +0 -0
  24. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/gitlab_projects_settings.egg-info/requires.txt +0 -0
  25. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/gitlab_projects_settings.egg-info/top_level.txt +0 -0
  26. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/mypy.ini +0 -0
  27. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/requirements/build.txt +0 -0
  28. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/requirements/deploy.txt +0 -0
  29. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/requirements/quality.txt +0 -0
  30. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/requirements/runtime.txt +0 -0
  31. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/setup.cfg +0 -0
  32. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/setup.py +0 -0
  33. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/src/__init__.py +0 -0
  34. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/src/__main__.py +0 -0
  35. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/src/cli/__init__.py +0 -0
  36. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/src/features/__init__.py +0 -0
  37. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/src/package/__init__.py +0 -0
  38. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/src/package/bundle.py +0 -0
  39. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/src/package/version.py +0 -0
  40. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/src/prints/__init__.py +0 -0
  41. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/src/prints/colors.py +0 -0
  42. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/src/system/__init__.py +0 -0
  43. {gitlab_projects_settings-2.0.2 → gitlab_projects_settings-3.0.0}/src/system/platform.py +0 -0
@@ -53,43 +53,6 @@ changelog:
53
53
  rules:
54
54
  - if: $CI_LOCAL
55
55
 
56
- readme:
57
- stage: development
58
- image: local:silent
59
- script:
60
- - |
61
- export COLUMNS=120
62
- mkdir -p ./.tmp/
63
- PACKAGE_NAME=$(grep '^PROJECT_NAME =' ./setup.py | cut -d"'" -f2)
64
- {
65
- echo ''
66
- echo '```yaml'
67
- alignments='[ ]\{2,\}'
68
- argument='[[:alnum:]][[:alnum:]_-]\{0,\}'
69
- letter='[[:alnum:]_]\{1\}'
70
- parameter='[-]\{1,2\}[[:alnum:]][[:alnum:]_-]\{0,\}'
71
- word='[[:alnum:]_-]\{1,\}'
72
- "${PACKAGE_NAME}" --help \
73
- | sed '1d; $d' \
74
- | sed "s/^\( ${parameter} ${word}${alignments}\)/\1# /g" \
75
- | sed "s/^\( ${parameter}${alignments}\)/\1# /g" \
76
- | sed "s/^\( ${parameter}, ${parameter}${alignments}\)/\1# /g" \
77
- | sed "s/^\( ${argument}${alignments}\)/\1# /g"
78
- echo '```'
79
- echo ''
80
- } >./.tmp/README.help.tmp
81
- - |
82
- lead='^<!-- readme-help-start -->$'
83
- tail='^<!-- readme-help-stop -->$'
84
- sed -i "/${lead}/,/${tail}/{ /${lead}/{ p; r ./.tmp/README.help.tmp
85
- }; /${tail}/p; d }" ./README.md | head -n 100
86
- - rm -f ./.tmp/README.help.tmp
87
- - |
88
- git -c color.diff=always --no-pager diff ./README.md | grep --color=never '.' && echo ''
89
- echo ' > README: Updated successfully'
90
- rules:
91
- - if: $CI_LOCAL
92
-
93
56
  # =============================================================================
94
57
  # Stage: prepare
95
58
 
@@ -192,6 +155,43 @@ install:
192
155
  rules:
193
156
  - if: $CI_LOCAL
194
157
 
158
+ readme:
159
+ stage: build
160
+ image: local:silent
161
+ script:
162
+ - |
163
+ export COLUMNS=120
164
+ mkdir -p ./.tmp/
165
+ PACKAGE_NAME=$(grep '^PROJECT_NAME =' ./setup.py | cut -d"'" -f2)
166
+ {
167
+ echo ''
168
+ echo '```yaml'
169
+ alignments='[ ]\{2,\}'
170
+ argument='[[:alnum:]][[:alnum:]_-]\{0,\}'
171
+ letter='[[:alnum:]_]\{1\}'
172
+ parameter='[-]\{1,2\}[[:alnum:]][[:alnum:]_-]\{0,\}'
173
+ word='[[:alnum:]_-]\{1,\}'
174
+ "${PACKAGE_NAME}" --help \
175
+ | sed '1d; $d' \
176
+ | sed "s/^\( ${parameter} ${word}${alignments}\)/\1# /g" \
177
+ | sed "s/^\( ${parameter}${alignments}\)/\1# /g" \
178
+ | sed "s/^\( ${parameter}, ${parameter}${alignments}\)/\1# /g" \
179
+ | sed "s/^\( ${argument}${alignments}\)/\1# /g"
180
+ echo '```'
181
+ echo ''
182
+ } >./.tmp/README.help.tmp
183
+ - |
184
+ lead='^<!-- readme-help-start -->$'
185
+ tail='^<!-- readme-help-stop -->$'
186
+ sed -i "/${lead}/,/${tail}/{ /${lead}/{ p; r ./.tmp/README.help.tmp
187
+ }; /${tail}/p; d }" ./README.md | head -n 100
188
+ - rm -f ./.tmp/README.help.tmp
189
+ - |
190
+ git -c color.diff=always --no-pager diff ./README.md | grep --color=never '.' && echo ''
191
+ echo ' > README: Updated successfully'
192
+ rules:
193
+ - if: $CI_LOCAL
194
+
195
195
  # =============================================================================
196
196
  # Stage: deploy
197
197
 
@@ -1,4 +1,47 @@
1
1
 
2
+ <a name="3.0.0"></a>
3
+ ## [3.0.0](https://gitlab.com/AdrianDC/gitlab-projects-settings/compare/2.1.0...3.0.0) (2024-05-06)
4
+
5
+ ### Bug Fixes
6
+
7
+ * **entrypoint:** resolve support for private user namespaces
8
+ * **entrypoint:** detect if GitLab actions can continue
9
+ * **entrypoint:** enforce against missing '.description' values
10
+ * **gitlab:** enforce 'group_delete' usage in '--dry-run' mode
11
+ * **gitlab:** delay groups deletion by 10s and projects by 5s
12
+ * **gitlab:** get all branches and tags upon 'list()' calls
13
+ * **gitlab:** get all members in 'project_reset_members'
14
+
15
+ ### Ci
16
+
17
+ * **gitlab-ci:** move 'readme' job after 'build' and local 'install'
18
+
19
+ ### Cleanups
20
+
21
+ * **gitlab:** minor comments changes in 'project_reset_features'
22
+
23
+ ### Features
24
+
25
+ * **entrypoint:** preserve main group description if exists
26
+ * **entrypoint:** always flush progress output logs
27
+ * **gitlab:** detect multiple branches to keep 'Merge requests'
28
+ * **gitlab:** detect 'Token Access' usage for 'CI/CD' features
29
+ * **namespaces:** migrate 'Helper' class to 'Namespaces' class
30
+
31
+
32
+ <a name="2.1.0"></a>
33
+ ## [2.1.0](https://gitlab.com/AdrianDC/gitlab-projects-settings/compare/2.0.2...2.1.0) (2024-04-28)
34
+
35
+ ### Bug Fixes
36
+
37
+ * **entrypoint:** fix project '--update-description' logs output
38
+
39
+ ### Features
40
+
41
+ * **entrypoint:** sort groups and projects recursively
42
+ * **entrypoint:** keep description if already contains group
43
+
44
+
2
45
  <a name="2.0.2"></a>
3
46
  ## [2.0.2](https://gitlab.com/AdrianDC/gitlab-projects-settings/compare/2.0.1...2.0.2) (2024-04-28)
4
47
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: gitlab-projects-settings
3
- Version: 2.0.2
3
+ Version: 3.0.0
4
4
  Summary: Configure GitLab groups and projects settings automatically
5
5
  Home-page: https://gitlab.com/AdrianDC/gitlab-projects-settings
6
6
  Author: Adrian DC
@@ -64,8 +64,9 @@ The following step is required before using the tool:
64
64
  ```yaml
65
65
  usage: gitlab-projects-settings [-h] [--version] [-t TOKEN] [--dry-run] [--exclude-group] [--exclude-subgroups]
66
66
  [--exclude-projects] [--reset-features] [--reset-members] [--set-avatar FILE]
67
- [--set-description TEXT] [--update-description] [--protect-branches]
68
- [--protect-tags LEVEL]
67
+ [--set-description TEXT] [--update-description] [--run-housekeeping]
68
+ [--archive-project | --unarchive-project] [--delete-group] [--delete-project]
69
+ [--protect-branches] [--protect-tags LEVEL]
69
70
  [gitlab] [path]
70
71
 
71
72
  gitlab-projects-settings: Configure GitLab groups and projects settings automatically
@@ -90,13 +91,20 @@ general settings arguments:
90
91
  --set-description TEXT # Set description of GitLab projects and groups
91
92
  --update-description # Update description of GitLab projects and groups automatically
92
93
 
94
+ advanced settings arguments:
95
+ --run-housekeeping # Run housekeeping of project or projects GitLab in groups
96
+ --archive-project # Archive project or projects in GitLab groups
97
+ --unarchive-project # Unarchive project or projects in GitLab groups
98
+ --delete-group # Delete group or groups in GitLab groups
99
+ --delete-project # Delete project or projects in GitLab groups
100
+
93
101
  repository settings arguments:
94
102
  --protect-branches # Protect branches with default master/main, develop and staging
95
103
  --protect-tags LEVEL # Protect tags at level [no-one,admins,maintainers,developers]
96
104
 
97
105
  positional arguments:
98
106
  gitlab # GitLab URL (default: https://gitlab.com)
99
- path # GitLab group or project path
107
+ path # GitLab group, user namespace or project path
100
108
  ```
101
109
 
102
110
  <!-- readme-help-stop -->
@@ -30,8 +30,9 @@ The following step is required before using the tool:
30
30
  ```yaml
31
31
  usage: gitlab-projects-settings [-h] [--version] [-t TOKEN] [--dry-run] [--exclude-group] [--exclude-subgroups]
32
32
  [--exclude-projects] [--reset-features] [--reset-members] [--set-avatar FILE]
33
- [--set-description TEXT] [--update-description] [--protect-branches]
34
- [--protect-tags LEVEL]
33
+ [--set-description TEXT] [--update-description] [--run-housekeeping]
34
+ [--archive-project | --unarchive-project] [--delete-group] [--delete-project]
35
+ [--protect-branches] [--protect-tags LEVEL]
35
36
  [gitlab] [path]
36
37
 
37
38
  gitlab-projects-settings: Configure GitLab groups and projects settings automatically
@@ -56,13 +57,20 @@ general settings arguments:
56
57
  --set-description TEXT # Set description of GitLab projects and groups
57
58
  --update-description # Update description of GitLab projects and groups automatically
58
59
 
60
+ advanced settings arguments:
61
+ --run-housekeeping # Run housekeeping of project or projects GitLab in groups
62
+ --archive-project # Archive project or projects in GitLab groups
63
+ --unarchive-project # Unarchive project or projects in GitLab groups
64
+ --delete-group # Delete group or groups in GitLab groups
65
+ --delete-project # Delete project or projects in GitLab groups
66
+
59
67
  repository settings arguments:
60
68
  --protect-branches # Protect branches with default master/main, develop and staging
61
69
  --protect-tags LEVEL # Protect tags at level [no-one,admins,maintainers,developers]
62
70
 
63
71
  positional arguments:
64
72
  gitlab # GitLab URL (default: https://gitlab.com)
65
- path # GitLab group or project path
73
+ path # GitLab group, user namespace or project path
66
74
  ```
67
75
 
68
76
  <!-- readme-help-stop -->
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: gitlab-projects-settings
3
- Version: 2.0.2
3
+ Version: 3.0.0
4
4
  Summary: Configure GitLab groups and projects settings automatically
5
5
  Home-page: https://gitlab.com/AdrianDC/gitlab-projects-settings
6
6
  Author: Adrian DC
@@ -64,8 +64,9 @@ The following step is required before using the tool:
64
64
  ```yaml
65
65
  usage: gitlab-projects-settings [-h] [--version] [-t TOKEN] [--dry-run] [--exclude-group] [--exclude-subgroups]
66
66
  [--exclude-projects] [--reset-features] [--reset-members] [--set-avatar FILE]
67
- [--set-description TEXT] [--update-description] [--protect-branches]
68
- [--protect-tags LEVEL]
67
+ [--set-description TEXT] [--update-description] [--run-housekeeping]
68
+ [--archive-project | --unarchive-project] [--delete-group] [--delete-project]
69
+ [--protect-branches] [--protect-tags LEVEL]
69
70
  [gitlab] [path]
70
71
 
71
72
  gitlab-projects-settings: Configure GitLab groups and projects settings automatically
@@ -90,13 +91,20 @@ general settings arguments:
90
91
  --set-description TEXT # Set description of GitLab projects and groups
91
92
  --update-description # Update description of GitLab projects and groups automatically
92
93
 
94
+ advanced settings arguments:
95
+ --run-housekeeping # Run housekeeping of project or projects GitLab in groups
96
+ --archive-project # Archive project or projects in GitLab groups
97
+ --unarchive-project # Unarchive project or projects in GitLab groups
98
+ --delete-group # Delete group or groups in GitLab groups
99
+ --delete-project # Delete project or projects in GitLab groups
100
+
93
101
  repository settings arguments:
94
102
  --protect-branches # Protect branches with default master/main, develop and staging
95
103
  --protect-tags LEVEL # Protect tags at level [no-one,admins,maintainers,developers]
96
104
 
97
105
  positional arguments:
98
106
  gitlab # GitLab URL (default: https://gitlab.com)
99
- path # GitLab group or project path
107
+ path # GitLab group, user namespace or project path
100
108
  ```
101
109
 
102
110
  <!-- readme-help-stop -->
@@ -35,4 +35,6 @@ src/package/version.py
35
35
  src/prints/__init__.py
36
36
  src/prints/colors.py
37
37
  src/system/__init__.py
38
- src/system/platform.py
38
+ src/system/platform.py
39
+ src/types/__init__.py
40
+ src/types/namespaces.py
@@ -0,0 +1,401 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Standard libraries
4
+ from argparse import Namespace
5
+
6
+ # Modules libraries
7
+ from gitlab.exceptions import GitlabGetError
8
+ from gitlab.v4.objects import Group as GitLabGroup, Project as GitLabProject, User as GitLabUser
9
+
10
+ # Components
11
+ from ..features.gitlab import GitLabFeature
12
+ from ..prints.colors import Colors
13
+ from ..system.platform import Platform
14
+ from ..types.namespaces import Namespaces
15
+
16
+ # Entrypoint class, pylint: disable=too-few-public-methods
17
+ class Entrypoint:
18
+
19
+ # CLI, pylint: disable=too-many-branches
20
+ @staticmethod
21
+ def cli(options: Namespace) -> bool:
22
+
23
+ # Variables
24
+ group: GitLabGroup = None
25
+ project: GitLabProject = None
26
+ user: GitLabUser = None
27
+
28
+ # Header
29
+ print(' ')
30
+
31
+ # GitLab client
32
+ gitlab = GitLabFeature(
33
+ options.gitlab,
34
+ options.token,
35
+ options.dry_run,
36
+ )
37
+ print(f'{Colors.BOLD} - GitLab host: '
38
+ f'{Colors.GREEN}{gitlab.url}'
39
+ f'{Colors.RESET}')
40
+ Platform.flush()
41
+
42
+ # GitLab path
43
+ try:
44
+ group = gitlab.group(options.path)
45
+ print(f'{Colors.BOLD} - GitLab group: '
46
+ f'{Colors.GREEN}{group.full_path}'
47
+ f'{Colors.CYAN} ({group.description})'
48
+ f'{Colors.RESET}')
49
+ print(' ')
50
+ Platform.flush()
51
+ except GitlabGetError as exception:
52
+ try:
53
+ if '/' in options.path:
54
+ raise TypeError from exception
55
+ user = gitlab.user(options.path)
56
+ namespace = gitlab.namespace(user.namespace_id)
57
+ print(f'{Colors.BOLD} - GitLab user namespace: '
58
+ f'{Colors.GREEN}{namespace.full_path}'
59
+ f'{Colors.CYAN} ({namespace.name})'
60
+ f'{Colors.RESET}')
61
+ print(' ')
62
+ Platform.flush()
63
+ except (GitlabGetError, TypeError):
64
+ project = gitlab.project(options.path)
65
+ print(f'{Colors.BOLD} - GitLab project: '
66
+ f'{Colors.GREEN}{project.path_with_namespace}'
67
+ f'{Colors.CYAN} ({project.description})'
68
+ f'{Colors.RESET}')
69
+ print(' ')
70
+ Platform.flush()
71
+
72
+ # Handle single project
73
+ if project:
74
+ Entrypoint.project(
75
+ options,
76
+ gitlab,
77
+ project.id,
78
+ )
79
+
80
+ # Handle group recursively
81
+ elif group:
82
+
83
+ # Handle group
84
+ if not options.exclude_group:
85
+ if not Entrypoint.group(
86
+ options,
87
+ gitlab,
88
+ group.id,
89
+ ):
90
+ return False
91
+
92
+ # Iterate through subgroups
93
+ if not options.exclude_subgroups:
94
+ for group_subgroup in sorted(
95
+ group.descendant_groups.list(
96
+ get_all=True,
97
+ include_subgroups=True,
98
+ order_by='path',
99
+ sort='asc',
100
+ ),
101
+ key=lambda item: item.full_path,
102
+ ):
103
+ if not Entrypoint.group(
104
+ options,
105
+ gitlab,
106
+ group_subgroup.id,
107
+ True,
108
+ ):
109
+ return False
110
+
111
+ # Iterate through projects
112
+ if not options.exclude_projects:
113
+ for group_project in sorted(
114
+ group.projects.list(
115
+ get_all=True,
116
+ include_subgroups=not options.exclude_subgroups,
117
+ order_by='path',
118
+ sort='asc',
119
+ ),
120
+ key=lambda item: item.path_with_namespace,
121
+ ):
122
+ if not Entrypoint.project(
123
+ options,
124
+ gitlab,
125
+ group_project.id,
126
+ ):
127
+ return False
128
+
129
+ # Handle user recursively
130
+ elif user:
131
+
132
+ # Iterate through projects
133
+ if not options.exclude_projects:
134
+ for user_project in sorted(
135
+ user.projects.list(
136
+ get_all=True,
137
+ order_by='path',
138
+ sort='asc',
139
+ ),
140
+ key=lambda item: item.path_with_namespace,
141
+ ):
142
+ if not Entrypoint.project(
143
+ options,
144
+ gitlab,
145
+ user_project.id,
146
+ ):
147
+ return False
148
+
149
+ # Result
150
+ return True
151
+
152
+ # Group
153
+ @staticmethod
154
+ def group(
155
+ options: Namespace,
156
+ gitlab: GitLabFeature,
157
+ criteria: str,
158
+ subgroup: bool = False,
159
+ ) -> bool:
160
+
161
+ # Acquire group
162
+ group = gitlab.group(criteria)
163
+
164
+ # Acquire parent group
165
+ parent_group: GitLabGroup = None
166
+ if group.parent_id:
167
+ parent_group = gitlab.group(group.parent_id)
168
+
169
+ # Get parent description
170
+ parent_description: str = ''
171
+ parent_name: str = ''
172
+ if parent_group:
173
+ parent_description = parent_group.description
174
+ parent_name = parent_group.name
175
+
176
+ # Show group details
177
+ group_type = 'subgroup' if subgroup else 'group'
178
+ print(f'{Colors.BOLD} - GitLab {group_type}: '
179
+ f'{Colors.YELLOW_LIGHT}{group.full_path} '
180
+ f'{Colors.CYAN}({group.description})'
181
+ f'{Colors.RESET}')
182
+ Platform.flush()
183
+
184
+ # Delete group
185
+ if options.delete_group:
186
+ gitlab.group_delete(criteria)
187
+ print(f'{Colors.BOLD} - Delete {group_type}: '
188
+ f'{Colors.GREEN}Success'
189
+ f'{Colors.RESET}')
190
+ print(' ')
191
+ Platform.flush()
192
+ return subgroup
193
+
194
+ # Set group description
195
+ if options.set_description:
196
+ gitlab.group_set_description(criteria, options.set_description)
197
+ print(f'{Colors.BOLD} - Set description: '
198
+ f'{Colors.CYAN}{options.set_description}'
199
+ f'{Colors.RESET}')
200
+ Platform.flush()
201
+
202
+ # Update group description
203
+ elif options.update_description:
204
+ parent_description_text: str = ''
205
+ if parent_name:
206
+ parent_description_text = ' - ' + Namespaces.describe(
207
+ name=parent_name,
208
+ description=parent_description,
209
+ )
210
+ if not group.description or subgroup and ( \
211
+ not parent_description_text or \
212
+ not group.description.endswith(f'{parent_description_text}') \
213
+ ):
214
+ description = f'{Namespaces.describe(name=group.name)}' \
215
+ f'{parent_description_text}'
216
+ gitlab.group_set_description(criteria, description)
217
+ print(f'{Colors.BOLD} - Updated description: '
218
+ f'{Colors.CYAN}{description}'
219
+ f'{Colors.RESET}')
220
+ Platform.flush()
221
+ else:
222
+ print(f'{Colors.BOLD} - Kept description: '
223
+ f'{Colors.GREEN}{group.description}'
224
+ f'{Colors.RESET}')
225
+ Platform.flush()
226
+
227
+ # Reset group members
228
+ if options.reset_members:
229
+ gitlab.group_reset_members(criteria)
230
+ print(f'{Colors.BOLD} - Reset members: '
231
+ f'{Colors.GREEN}Success'
232
+ f'{Colors.RESET}')
233
+ Platform.flush()
234
+
235
+ # Set group avatar
236
+ if options.set_avatar:
237
+ gitlab.group_set_avatar(criteria, options.set_avatar)
238
+ print(f'{Colors.BOLD} - Set avatar: '
239
+ f'{Colors.CYAN}{options.set_avatar}'
240
+ f'{Colors.RESET}')
241
+ Platform.flush()
242
+
243
+ # Footer
244
+ print(' ')
245
+ Platform.flush()
246
+
247
+ # Result
248
+ return True
249
+
250
+ # Project, pylint: disable=too-many-branches,too-many-statements
251
+ @staticmethod
252
+ def project(
253
+ options: Namespace,
254
+ gitlab: GitLabFeature,
255
+ criteria: str,
256
+ ) -> bool:
257
+
258
+ # Acquire project
259
+ project = gitlab.project(criteria)
260
+
261
+ # Show project details
262
+ print(f'{Colors.BOLD} - GitLab project: '
263
+ f'{Colors.YELLOW_LIGHT}{project.path_with_namespace} '
264
+ f'{Colors.CYAN}({project.description})'
265
+ f'{Colors.RESET}')
266
+ Platform.flush()
267
+
268
+ # Delete project
269
+ if options.delete_project:
270
+ gitlab.project_delete(criteria)
271
+ print(f'{Colors.BOLD} - Delete project: '
272
+ f'{Colors.GREEN}Success'
273
+ f'{Colors.RESET}')
274
+ print(' ')
275
+ Platform.flush()
276
+ return True
277
+
278
+ # Set project description
279
+ if options.set_description:
280
+ gitlab.project_set_description(criteria, options.set_description)
281
+ print(f'{Colors.BOLD} - Set description: '
282
+ f'{Colors.CYAN}{options.set_description}'
283
+ f'{Colors.RESET}')
284
+ Platform.flush()
285
+
286
+ # Update project description
287
+ elif options.update_description:
288
+ namespace_description: str
289
+ if project.namespace['kind'] == 'user':
290
+ namespace = gitlab.namespace(project.namespace['id'])
291
+ namespace_description = namespace.name
292
+ else:
293
+ group = gitlab.group(project.namespace['id'])
294
+ namespace_description = Namespaces.describe(
295
+ name=group.name,
296
+ description=group.description,
297
+ )
298
+ if not project.description or \
299
+ not project.description.endswith(f' - {namespace_description}'):
300
+ description = f'{Namespaces.describe(name=project.name)}' \
301
+ f' - {namespace_description}'
302
+ gitlab.project_set_description(criteria, description)
303
+ print(f'{Colors.BOLD} - Updated description: '
304
+ f'{Colors.CYAN}{description}'
305
+ f'{Colors.RESET}')
306
+ Platform.flush()
307
+ else:
308
+ print(f'{Colors.BOLD} - Kept description: '
309
+ f'{Colors.GREEN}{project.description}'
310
+ f'{Colors.RESET}')
311
+ Platform.flush()
312
+
313
+ # Reset project features
314
+ if options.reset_features:
315
+ features = ', '.join(gitlab.project_reset_features(criteria))
316
+ if features:
317
+ print(f'{Colors.BOLD} - Reset features: '
318
+ f'{Colors.CYAN}{features}'
319
+ f'{Colors.RESET}')
320
+ Platform.flush()
321
+ else:
322
+ print(f'{Colors.BOLD} - Reset features: '
323
+ f'{Colors.GREEN}Already done'
324
+ f'{Colors.RESET}')
325
+ Platform.flush()
326
+
327
+ # Reset project members
328
+ if options.reset_members:
329
+ gitlab.project_reset_members(criteria)
330
+ print(f'{Colors.BOLD} - Reset members: '
331
+ f'{Colors.GREEN}Success'
332
+ f'{Colors.RESET}')
333
+ Platform.flush()
334
+
335
+ # Set project avatar
336
+ if options.set_avatar:
337
+ gitlab.project_set_avatar(criteria, options.set_avatar)
338
+ print(f'{Colors.BOLD} - Set avatar: '
339
+ f'{Colors.CYAN}{options.set_avatar}'
340
+ f'{Colors.RESET}')
341
+ Platform.flush()
342
+
343
+ # Run project housekeeping
344
+ if options.run_housekeeping:
345
+ gitlab.project_run_housekeeping(criteria)
346
+ print(f'{Colors.BOLD} - Ran housekeeping: '
347
+ f'{Colors.GREEN}Success'
348
+ f'{Colors.RESET}')
349
+ Platform.flush()
350
+
351
+ # Archive project
352
+ if options.archive_project:
353
+ gitlab.project_set_archive(criteria, True)
354
+ print(f'{Colors.BOLD} - Archive project: '
355
+ f'{Colors.GREEN}Success'
356
+ f'{Colors.RESET}')
357
+ Platform.flush()
358
+
359
+ # Unarchive project
360
+ elif options.unarchive_project:
361
+ gitlab.project_set_archive(criteria, False)
362
+ print(f'{Colors.BOLD} - Unarchive project: '
363
+ f'{Colors.GREEN}Success'
364
+ f'{Colors.RESET}')
365
+ Platform.flush()
366
+
367
+ # Protect project branches
368
+ if options.protect_branches:
369
+ branches = ', '.join(gitlab.project_protect_branches(criteria))
370
+ if branches:
371
+ print(f'{Colors.BOLD} - Protecting branches: '
372
+ f'{Colors.CYAN}{branches}'
373
+ f'{Colors.RESET}')
374
+ Platform.flush()
375
+ else:
376
+ print(f'{Colors.BOLD} - Protecting branches: '
377
+ f'{Colors.GREEN}Already done'
378
+ f'{Colors.RESET}')
379
+ Platform.flush()
380
+
381
+ # Protect project tags
382
+ if options.protect_tags:
383
+ tags = ', '.join(gitlab.project_protect_tags(criteria, options.protect_tags))
384
+ if tags:
385
+ print(f'{Colors.BOLD} - Protecting tags: '
386
+ f'{Colors.CYAN}{tags}'
387
+ f'{Colors.GREEN} (level: {options.protect_tags})'
388
+ f'{Colors.RESET}')
389
+ Platform.flush()
390
+ else:
391
+ print(f'{Colors.BOLD} - Protecting tags: '
392
+ f'{Colors.GREEN}Already done'
393
+ f'{Colors.RESET}')
394
+ Platform.flush()
395
+
396
+ # Footer
397
+ print(' ')
398
+ Platform.flush()
399
+
400
+ # Result
401
+ return True