gitlabber 1.2.6__tar.gz → 1.2.8__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.
- {gitlabber-1.2.6/gitlabber.egg-info → gitlabber-1.2.8}/PKG-INFO +27 -11
- {gitlabber-1.2.6 → gitlabber-1.2.8}/README.rst +8 -4
- gitlabber-1.2.8/gitlabber/__init__.py +2 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/gitlabber/cli.py +2 -9
- {gitlabber-1.2.6 → gitlabber-1.2.8}/gitlabber/gitlab_tree.py +27 -16
- {gitlabber-1.2.6 → gitlabber-1.2.8/gitlabber.egg-info}/PKG-INFO +27 -11
- {gitlabber-1.2.6 → gitlabber-1.2.8}/gitlabber.egg-info/SOURCES.txt +2 -13
- {gitlabber-1.2.6 → gitlabber-1.2.8}/gitlabber.egg-info/requires.txt +6 -0
- gitlabber-1.2.8/pyproject.toml +79 -0
- gitlabber-1.2.8/setup.cfg +10 -0
- gitlabber-1.2.8/setup.py +3 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/gitlab_test_utils.py +16 -5
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/test_e2e.py +16 -6
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/test_gitlab_tree.py +73 -1
- gitlabber-1.2.6/gitlabber/__init__.py +0 -1
- gitlabber-1.2.6/setup.cfg +0 -24
- gitlabber-1.2.6/setup.py +0 -89
- gitlabber-1.2.6/tests/__pycache__/__init__.cpython-311.pyc +0 -0
- gitlabber-1.2.6/tests/__pycache__/gitlab_test_utils.cpython-311.pyc +0 -0
- gitlabber-1.2.6/tests/__pycache__/io_test_util.cpython-311.pyc +0 -0
- gitlabber-1.2.6/tests/__pycache__/test_archive.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-1.2.6/tests/__pycache__/test_cli.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-1.2.6/tests/__pycache__/test_e2e.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-1.2.6/tests/__pycache__/test_format.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-1.2.6/tests/__pycache__/test_git.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-1.2.6/tests/__pycache__/test_gitlab_tree.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-1.2.6/tests/__pycache__/test_integration.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-1.2.6/tests/__pycache__/test_method.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-1.2.6/tests/__pycache__/test_naming.cpython-311-pytest-8.2.2.pyc +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/LICENSE.txt +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/MANIFEST.in +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/gitlabber/__main__.py +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/gitlabber/archive.py +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/gitlabber/format.py +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/gitlabber/git.py +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/gitlabber/method.py +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/gitlabber/naming.py +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/gitlabber/progress.py +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/gitlabber.egg-info/dependency_links.txt +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/gitlabber.egg-info/entry_points.txt +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/gitlabber.egg-info/top_level.txt +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/__init__.py +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/io_test_util.py +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/test-input.yaml +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/test-output.json +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/test-output.tree +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/test-output.yaml +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/test_archive.py +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/test_cli.py +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/test_format.py +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/test_git.py +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/test_integration.py +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/test_method.py +0 -0
- {gitlabber-1.2.6 → gitlabber-1.2.8}/tests/test_naming.py +0 -0
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: gitlabber
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.8
|
|
4
4
|
Summary: A Gitlab clone/pull utility for backing up or cloning Gitlab groups
|
|
5
|
-
|
|
6
|
-
Download-URL: https://github.com/ezbz/gitlabber/archive/main.zip
|
|
7
|
-
Author: Erez Mazor
|
|
8
|
-
Author-email: erezmazor@gmail.com
|
|
5
|
+
Author-email: Erez Mazor <erezmazor@gmail.com>
|
|
9
6
|
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/ezbz/gitlabber
|
|
8
|
+
Project-URL: Download, https://github.com/ezbz/gitlabber/archive/main.zip
|
|
10
9
|
Keywords: gitlab,python,cli
|
|
11
10
|
Classifier: Development Status :: 4 - Beta
|
|
12
11
|
Classifier: Intended Audience :: Developers
|
|
@@ -15,14 +14,27 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
15
14
|
Classifier: Natural Language :: English
|
|
16
15
|
Classifier: Operating System :: OS Independent
|
|
17
16
|
Classifier: Programming Language :: Python :: 3
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
19
17
|
Classifier: Programming Language :: Python :: 3.9
|
|
20
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
22
|
Requires-Python: >=3
|
|
24
23
|
Description-Content-Type: text/x-rst
|
|
25
24
|
License-File: LICENSE.txt
|
|
25
|
+
Requires-Dist: docopt
|
|
26
|
+
Requires-Dist: anytree
|
|
27
|
+
Requires-Dist: globre
|
|
28
|
+
Requires-Dist: pyyaml
|
|
29
|
+
Requires-Dist: tqdm
|
|
30
|
+
Requires-Dist: GitPython
|
|
31
|
+
Requires-Dist: python-gitlab
|
|
32
|
+
Provides-Extra: test
|
|
33
|
+
Requires-Dist: coverage; extra == "test"
|
|
34
|
+
Requires-Dist: pytest; extra == "test"
|
|
35
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
36
|
+
Requires-Dist: pytest-integration; extra == "test"
|
|
37
|
+
Dynamic: license-file
|
|
26
38
|
|
|
27
39
|
.. image:: https://github.com/ezbz/gitlabber/actions/workflows/python-app.yml/badge.svg?branch=master
|
|
28
40
|
:target: https://github.com/ezbz/gitlabber/actions/workflows/python-app.yml
|
|
@@ -40,7 +52,7 @@ License-File: LICENSE.txt
|
|
|
40
52
|
:target: https://pypi.python.org/pypi/gitlabber/
|
|
41
53
|
|
|
42
54
|
.. image:: https://readthedocs.org/projects/gitlabber/badge/?version=latest&style=plastic
|
|
43
|
-
:target: https://
|
|
55
|
+
:target: https://app.readthedocs.org/projects/gitlabber/
|
|
44
56
|
|
|
45
57
|
|
|
46
58
|
Gitlabber
|
|
@@ -104,7 +116,7 @@ Usage
|
|
|
104
116
|
|
|
105
117
|
* To see how to use glob patterns and regex to filter tree nodes, see the `globre project page <https://pypi.org/project/globre/#details>`_.
|
|
106
118
|
|
|
107
|
-
* Include/Exclude patterns do not work at the API level but work on the results returned from the API, for large Gitlab installations this can take a lot of time, if you need to reduce the amound of API calls for such projects use the ``--group-search`` parameter to search only for the top level groups the interest you using the `Gitlab Group Search API <https://docs.gitlab.com/ee/api/groups.html#search-for-group>` which allows you to do a partial like query for a Group's path or name
|
|
119
|
+
* Include/Exclude patterns do not work at the API level but work on the results returned from the API, for large Gitlab installations this can take a lot of time, if you need to reduce the amound of API calls for such projects use the ``--group-search`` parameter to search only for the top level groups the interest you using the `Gitlab Group Search API <https://docs.gitlab.com/ee/api/groups.html#search-for-group>`_ which allows you to do a partial like query for a Group's path or name
|
|
108
120
|
|
|
109
121
|
* Cloning vs Pulling: when running Gitlabber consecutively with the same parameters, it will scan the local tree structure; if the project directory exists and is a valid git repository (has .git folder in it) Gitlabber will perform a git pull in the directory, otherwise the project directory will be created and the GitLab project will be cloned into it.
|
|
110
122
|
|
|
@@ -145,7 +157,6 @@ Usage
|
|
|
145
157
|
comma delimited list of glob patterns of paths to projects or groups to exclude from clone/pull
|
|
146
158
|
-r, --recursive clone/pull git submodules recursively
|
|
147
159
|
-F, --use-fetch clone/fetch git repository (mirrored repositories)
|
|
148
|
-
-d, --dont-checkout don't checkout pulled git repository
|
|
149
160
|
-s, --include-shared include shared projects in the results
|
|
150
161
|
-g term, --group-search term
|
|
151
162
|
only include groups matching the search term, filtering done at the API level (useful for large projects, see: https://docs.gitlab.com/ee/api/groups.html#search-for-group works with partial names of path or name)
|
|
@@ -174,7 +185,7 @@ Usage
|
|
|
174
185
|
clone projects that start with a case insensitive 'w' using a regular expression:
|
|
175
186
|
gitlabber -i '/{[w].*}' .
|
|
176
187
|
|
|
177
|
-
clone
|
|
188
|
+
clone the personal projects to username-personal-projects
|
|
178
189
|
gitlabber -U .
|
|
179
190
|
|
|
180
191
|
perform a shallow clone of the git repositories
|
|
@@ -201,3 +212,8 @@ Known Limitations
|
|
|
201
212
|
* Renaming, moving and deleting projects: Gitlabber doesn't maintain local tree state (projects and groups). For that reason is does not rename move or delete local projects when they are modified on the server. When projects are moved or renamed, Gitlabber will clone them again under their new name or location. When deleted, Gitlabber will not delete the local project.
|
|
202
213
|
* Folder naming strategy: Consecutively running Gitlabber with different values for the ``-n`` parameter will produce undesirable results. Use the same value as previous runs, or simply don't change it from the default (project name).
|
|
203
214
|
* If you're going to clone a large number of projects, observe rate limits `for gitlab.com <https://docs.gitlab.com/ee/user/gitlab_com/index.html#gitlabcom-specific-rate-limits/>`_, and `for on-premise installations <https://docs.gitlab.com/ee/security/rate_limits.html>`_.
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
Links
|
|
218
|
+
-----
|
|
219
|
+
* Gitlabber `tutorial <https://medium.com/@natskvi/clone-all-your-gitlab-groups-repos-before-starting-to-code-dd559ec5c8d6>`_ by nsk
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
:target: https://pypi.python.org/pypi/gitlabber/
|
|
15
15
|
|
|
16
16
|
.. image:: https://readthedocs.org/projects/gitlabber/badge/?version=latest&style=plastic
|
|
17
|
-
:target: https://
|
|
17
|
+
:target: https://app.readthedocs.org/projects/gitlabber/
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
Gitlabber
|
|
@@ -78,7 +78,7 @@ Usage
|
|
|
78
78
|
|
|
79
79
|
* To see how to use glob patterns and regex to filter tree nodes, see the `globre project page <https://pypi.org/project/globre/#details>`_.
|
|
80
80
|
|
|
81
|
-
* Include/Exclude patterns do not work at the API level but work on the results returned from the API, for large Gitlab installations this can take a lot of time, if you need to reduce the amound of API calls for such projects use the ``--group-search`` parameter to search only for the top level groups the interest you using the `Gitlab Group Search API <https://docs.gitlab.com/ee/api/groups.html#search-for-group>` which allows you to do a partial like query for a Group's path or name
|
|
81
|
+
* Include/Exclude patterns do not work at the API level but work on the results returned from the API, for large Gitlab installations this can take a lot of time, if you need to reduce the amound of API calls for such projects use the ``--group-search`` parameter to search only for the top level groups the interest you using the `Gitlab Group Search API <https://docs.gitlab.com/ee/api/groups.html#search-for-group>`_ which allows you to do a partial like query for a Group's path or name
|
|
82
82
|
|
|
83
83
|
* Cloning vs Pulling: when running Gitlabber consecutively with the same parameters, it will scan the local tree structure; if the project directory exists and is a valid git repository (has .git folder in it) Gitlabber will perform a git pull in the directory, otherwise the project directory will be created and the GitLab project will be cloned into it.
|
|
84
84
|
|
|
@@ -119,7 +119,6 @@ Usage
|
|
|
119
119
|
comma delimited list of glob patterns of paths to projects or groups to exclude from clone/pull
|
|
120
120
|
-r, --recursive clone/pull git submodules recursively
|
|
121
121
|
-F, --use-fetch clone/fetch git repository (mirrored repositories)
|
|
122
|
-
-d, --dont-checkout don't checkout pulled git repository
|
|
123
122
|
-s, --include-shared include shared projects in the results
|
|
124
123
|
-g term, --group-search term
|
|
125
124
|
only include groups matching the search term, filtering done at the API level (useful for large projects, see: https://docs.gitlab.com/ee/api/groups.html#search-for-group works with partial names of path or name)
|
|
@@ -148,7 +147,7 @@ Usage
|
|
|
148
147
|
clone projects that start with a case insensitive 'w' using a regular expression:
|
|
149
148
|
gitlabber -i '/{[w].*}' .
|
|
150
149
|
|
|
151
|
-
clone
|
|
150
|
+
clone the personal projects to username-personal-projects
|
|
152
151
|
gitlabber -U .
|
|
153
152
|
|
|
154
153
|
perform a shallow clone of the git repositories
|
|
@@ -175,3 +174,8 @@ Known Limitations
|
|
|
175
174
|
* Renaming, moving and deleting projects: Gitlabber doesn't maintain local tree state (projects and groups). For that reason is does not rename move or delete local projects when they are modified on the server. When projects are moved or renamed, Gitlabber will clone them again under their new name or location. When deleted, Gitlabber will not delete the local project.
|
|
176
175
|
* Folder naming strategy: Consecutively running Gitlabber with different values for the ``-n`` parameter will produce undesirable results. Use the same value as previous runs, or simply don't change it from the default (project name).
|
|
177
176
|
* If you're going to clone a large number of projects, observe rate limits `for gitlab.com <https://docs.gitlab.com/ee/user/gitlab_com/index.html#gitlabcom-specific-rate-limits/>`_, and `for on-premise installations <https://docs.gitlab.com/ee/security/rate_limits.html>`_.
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
Links
|
|
180
|
+
-----
|
|
181
|
+
* Gitlabber `tutorial <https://medium.com/@natskvi/clone-all-your-gitlab-groups-repos-before-starting-to-code-dd559ec5c8d6>`_ by nsk
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
import os
|
|
3
2
|
import sys
|
|
4
3
|
import logging
|
|
@@ -73,7 +72,7 @@ def config_logging(args):
|
|
|
73
72
|
|
|
74
73
|
|
|
75
74
|
def parse_args(argv=None):
|
|
76
|
-
example_text = '''examples:
|
|
75
|
+
example_text = r'''examples:
|
|
77
76
|
|
|
78
77
|
clone an entire gitlab tree using a url and a token:
|
|
79
78
|
gitlabber -t <personal access token> -u <gitlab url>
|
|
@@ -93,7 +92,7 @@ def parse_args(argv=None):
|
|
|
93
92
|
clone projects that start with a case insensitive 'w' using a regular expression:
|
|
94
93
|
gitlabber -i '/{[w].*}' .
|
|
95
94
|
|
|
96
|
-
clone
|
|
95
|
+
clone the user personal projects to username-personal-projects
|
|
97
96
|
gitlabber -U .
|
|
98
97
|
|
|
99
98
|
perform a shallow clone of the git repositories
|
|
@@ -200,12 +199,6 @@ def parse_args(argv=None):
|
|
|
200
199
|
action='store_true',
|
|
201
200
|
default=False,
|
|
202
201
|
help='clone/fetch git repository (mirrored repositories)')
|
|
203
|
-
parser.add_argument(
|
|
204
|
-
'-d',
|
|
205
|
-
'--dont-checkout',
|
|
206
|
-
action='store_true',
|
|
207
|
-
default=False,
|
|
208
|
-
help="don't checkout pulled git repository")
|
|
209
202
|
parser.add_argument(
|
|
210
203
|
'-s',
|
|
211
204
|
'--include-shared',
|
|
@@ -119,26 +119,37 @@ class GitlabTree:
|
|
|
119
119
|
projects = group.projects.list(archived=self.archived, with_shared=self.include_shared, get_all=True)
|
|
120
120
|
self.progress.update_progress_length(len(projects))
|
|
121
121
|
self.add_projects(parent, projects)
|
|
122
|
+
|
|
123
|
+
if self.include_shared and hasattr(group, 'shared_projects'):
|
|
124
|
+
shared_projects = group.shared_projects.list(get_all=True)
|
|
125
|
+
self.progress.update_progress_length(len(shared_projects))
|
|
126
|
+
self.add_projects(parent, shared_projects)
|
|
122
127
|
except GitlabListError as error:
|
|
123
128
|
log.error(f"Error getting projects on {group.name} id: [{group.id}] error message: [{error.error_message}]")
|
|
124
129
|
|
|
125
130
|
def get_subgroups(self, group, parent):
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
131
|
+
try:
|
|
132
|
+
subgroups = group.subgroups.list(as_list=False, get_all=True)
|
|
133
|
+
self.progress.update_progress_length(len(subgroups))
|
|
134
|
+
for subgroup_def in subgroups:
|
|
135
|
+
try:
|
|
136
|
+
subgroup = self.gitlab.groups.get(subgroup_def.id)
|
|
137
|
+
subgroup_id = subgroup.name if self.naming == FolderNaming.NAME else subgroup.path
|
|
138
|
+
node = self.make_node("subgroup", subgroup_id, parent, url=subgroup.web_url)
|
|
139
|
+
self.progress.show_progress(node.name, 'group')
|
|
140
|
+
self.get_subgroups(subgroup, node)
|
|
141
|
+
self.get_projects(subgroup, node)
|
|
142
|
+
except GitlabGetError as error:
|
|
143
|
+
if error.response_code == 404:
|
|
144
|
+
log.error(f"{error.response_code} error while getting subgroup with name: {group.name} [id: {group.id}]. Check your permissions as you may not have access to it. Message: {error.error_message}")
|
|
145
|
+
continue
|
|
146
|
+
else:
|
|
147
|
+
raise error
|
|
148
|
+
except GitlabListError as error:
|
|
149
|
+
if error.response_code == 404:
|
|
150
|
+
log.error(f"{error.response_code} error while listing subgroup with name: {group.name} [id: {group.id}]. Check your permissions as you may not have access to it. Message: {error.error_message}")
|
|
151
|
+
else:
|
|
152
|
+
raise error
|
|
142
153
|
|
|
143
154
|
def load_gitlab_tree(self):
|
|
144
155
|
log.debug(f"Starting group search with archived: {self.archived} search term: {self.group_search}")
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: gitlabber
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.8
|
|
4
4
|
Summary: A Gitlab clone/pull utility for backing up or cloning Gitlab groups
|
|
5
|
-
|
|
6
|
-
Download-URL: https://github.com/ezbz/gitlabber/archive/main.zip
|
|
7
|
-
Author: Erez Mazor
|
|
8
|
-
Author-email: erezmazor@gmail.com
|
|
5
|
+
Author-email: Erez Mazor <erezmazor@gmail.com>
|
|
9
6
|
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/ezbz/gitlabber
|
|
8
|
+
Project-URL: Download, https://github.com/ezbz/gitlabber/archive/main.zip
|
|
10
9
|
Keywords: gitlab,python,cli
|
|
11
10
|
Classifier: Development Status :: 4 - Beta
|
|
12
11
|
Classifier: Intended Audience :: Developers
|
|
@@ -15,14 +14,27 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
15
14
|
Classifier: Natural Language :: English
|
|
16
15
|
Classifier: Operating System :: OS Independent
|
|
17
16
|
Classifier: Programming Language :: Python :: 3
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
19
17
|
Classifier: Programming Language :: Python :: 3.9
|
|
20
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
22
|
Requires-Python: >=3
|
|
24
23
|
Description-Content-Type: text/x-rst
|
|
25
24
|
License-File: LICENSE.txt
|
|
25
|
+
Requires-Dist: docopt
|
|
26
|
+
Requires-Dist: anytree
|
|
27
|
+
Requires-Dist: globre
|
|
28
|
+
Requires-Dist: pyyaml
|
|
29
|
+
Requires-Dist: tqdm
|
|
30
|
+
Requires-Dist: GitPython
|
|
31
|
+
Requires-Dist: python-gitlab
|
|
32
|
+
Provides-Extra: test
|
|
33
|
+
Requires-Dist: coverage; extra == "test"
|
|
34
|
+
Requires-Dist: pytest; extra == "test"
|
|
35
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
36
|
+
Requires-Dist: pytest-integration; extra == "test"
|
|
37
|
+
Dynamic: license-file
|
|
26
38
|
|
|
27
39
|
.. image:: https://github.com/ezbz/gitlabber/actions/workflows/python-app.yml/badge.svg?branch=master
|
|
28
40
|
:target: https://github.com/ezbz/gitlabber/actions/workflows/python-app.yml
|
|
@@ -40,7 +52,7 @@ License-File: LICENSE.txt
|
|
|
40
52
|
:target: https://pypi.python.org/pypi/gitlabber/
|
|
41
53
|
|
|
42
54
|
.. image:: https://readthedocs.org/projects/gitlabber/badge/?version=latest&style=plastic
|
|
43
|
-
:target: https://
|
|
55
|
+
:target: https://app.readthedocs.org/projects/gitlabber/
|
|
44
56
|
|
|
45
57
|
|
|
46
58
|
Gitlabber
|
|
@@ -104,7 +116,7 @@ Usage
|
|
|
104
116
|
|
|
105
117
|
* To see how to use glob patterns and regex to filter tree nodes, see the `globre project page <https://pypi.org/project/globre/#details>`_.
|
|
106
118
|
|
|
107
|
-
* Include/Exclude patterns do not work at the API level but work on the results returned from the API, for large Gitlab installations this can take a lot of time, if you need to reduce the amound of API calls for such projects use the ``--group-search`` parameter to search only for the top level groups the interest you using the `Gitlab Group Search API <https://docs.gitlab.com/ee/api/groups.html#search-for-group>` which allows you to do a partial like query for a Group's path or name
|
|
119
|
+
* Include/Exclude patterns do not work at the API level but work on the results returned from the API, for large Gitlab installations this can take a lot of time, if you need to reduce the amound of API calls for such projects use the ``--group-search`` parameter to search only for the top level groups the interest you using the `Gitlab Group Search API <https://docs.gitlab.com/ee/api/groups.html#search-for-group>`_ which allows you to do a partial like query for a Group's path or name
|
|
108
120
|
|
|
109
121
|
* Cloning vs Pulling: when running Gitlabber consecutively with the same parameters, it will scan the local tree structure; if the project directory exists and is a valid git repository (has .git folder in it) Gitlabber will perform a git pull in the directory, otherwise the project directory will be created and the GitLab project will be cloned into it.
|
|
110
122
|
|
|
@@ -145,7 +157,6 @@ Usage
|
|
|
145
157
|
comma delimited list of glob patterns of paths to projects or groups to exclude from clone/pull
|
|
146
158
|
-r, --recursive clone/pull git submodules recursively
|
|
147
159
|
-F, --use-fetch clone/fetch git repository (mirrored repositories)
|
|
148
|
-
-d, --dont-checkout don't checkout pulled git repository
|
|
149
160
|
-s, --include-shared include shared projects in the results
|
|
150
161
|
-g term, --group-search term
|
|
151
162
|
only include groups matching the search term, filtering done at the API level (useful for large projects, see: https://docs.gitlab.com/ee/api/groups.html#search-for-group works with partial names of path or name)
|
|
@@ -174,7 +185,7 @@ Usage
|
|
|
174
185
|
clone projects that start with a case insensitive 'w' using a regular expression:
|
|
175
186
|
gitlabber -i '/{[w].*}' .
|
|
176
187
|
|
|
177
|
-
clone
|
|
188
|
+
clone the personal projects to username-personal-projects
|
|
178
189
|
gitlabber -U .
|
|
179
190
|
|
|
180
191
|
perform a shallow clone of the git repositories
|
|
@@ -201,3 +212,8 @@ Known Limitations
|
|
|
201
212
|
* Renaming, moving and deleting projects: Gitlabber doesn't maintain local tree state (projects and groups). For that reason is does not rename move or delete local projects when they are modified on the server. When projects are moved or renamed, Gitlabber will clone them again under their new name or location. When deleted, Gitlabber will not delete the local project.
|
|
202
213
|
* Folder naming strategy: Consecutively running Gitlabber with different values for the ``-n`` parameter will produce undesirable results. Use the same value as previous runs, or simply don't change it from the default (project name).
|
|
203
214
|
* If you're going to clone a large number of projects, observe rate limits `for gitlab.com <https://docs.gitlab.com/ee/user/gitlab_com/index.html#gitlabcom-specific-rate-limits/>`_, and `for on-premise installations <https://docs.gitlab.com/ee/security/rate_limits.html>`_.
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
Links
|
|
218
|
+
-----
|
|
219
|
+
* Gitlabber `tutorial <https://medium.com/@natskvi/clone-all-your-gitlab-groups-repos-before-starting-to-code-dd559ec5c8d6>`_ by nsk
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
LICENSE.txt
|
|
2
2
|
MANIFEST.in
|
|
3
3
|
README.rst
|
|
4
|
+
pyproject.toml
|
|
4
5
|
setup.cfg
|
|
5
6
|
setup.py
|
|
6
7
|
gitlabber/__init__.py
|
|
@@ -34,16 +35,4 @@ tests/test_git.py
|
|
|
34
35
|
tests/test_gitlab_tree.py
|
|
35
36
|
tests/test_integration.py
|
|
36
37
|
tests/test_method.py
|
|
37
|
-
tests/test_naming.py
|
|
38
|
-
tests/__pycache__/__init__.cpython-311.pyc
|
|
39
|
-
tests/__pycache__/gitlab_test_utils.cpython-311.pyc
|
|
40
|
-
tests/__pycache__/io_test_util.cpython-311.pyc
|
|
41
|
-
tests/__pycache__/test_archive.cpython-311-pytest-8.2.2.pyc
|
|
42
|
-
tests/__pycache__/test_cli.cpython-311-pytest-8.2.2.pyc
|
|
43
|
-
tests/__pycache__/test_e2e.cpython-311-pytest-8.2.2.pyc
|
|
44
|
-
tests/__pycache__/test_format.cpython-311-pytest-8.2.2.pyc
|
|
45
|
-
tests/__pycache__/test_git.cpython-311-pytest-8.2.2.pyc
|
|
46
|
-
tests/__pycache__/test_gitlab_tree.cpython-311-pytest-8.2.2.pyc
|
|
47
|
-
tests/__pycache__/test_integration.cpython-311-pytest-8.2.2.pyc
|
|
48
|
-
tests/__pycache__/test_method.cpython-311-pytest-8.2.2.pyc
|
|
49
|
-
tests/__pycache__/test_naming.cpython-311-pytest-8.2.2.pyc
|
|
38
|
+
tests/test_naming.py
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=45", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "gitlabber"
|
|
7
|
+
version = "1.2.8"
|
|
8
|
+
description = "A Gitlab clone/pull utility for backing up or cloning Gitlab groups"
|
|
9
|
+
readme = "README.rst"
|
|
10
|
+
requires-python = ">=3"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Erez Mazor", email = "erezmazor@gmail.com"},
|
|
14
|
+
]
|
|
15
|
+
keywords = ["gitlab", "python", "cli"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Topic :: Utilities",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Natural Language :: English",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.9",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
29
|
+
]
|
|
30
|
+
dependencies = [
|
|
31
|
+
"docopt",
|
|
32
|
+
"anytree",
|
|
33
|
+
"globre",
|
|
34
|
+
"pyyaml",
|
|
35
|
+
"tqdm",
|
|
36
|
+
"GitPython",
|
|
37
|
+
"python-gitlab",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.optional-dependencies]
|
|
41
|
+
test = [
|
|
42
|
+
"coverage",
|
|
43
|
+
"pytest",
|
|
44
|
+
"pytest-cov",
|
|
45
|
+
"pytest-integration",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[project.urls]
|
|
49
|
+
Homepage = "https://github.com/ezbz/gitlabber"
|
|
50
|
+
Download = "https://github.com/ezbz/gitlabber/archive/main.zip"
|
|
51
|
+
|
|
52
|
+
[project.scripts]
|
|
53
|
+
gitlabber = "gitlabber.cli:main"
|
|
54
|
+
|
|
55
|
+
[tool.setuptools]
|
|
56
|
+
packages = ["gitlabber"]
|
|
57
|
+
include-package-data = true
|
|
58
|
+
|
|
59
|
+
[tool.pytest.ini_options]
|
|
60
|
+
addopts = [
|
|
61
|
+
"-vv",
|
|
62
|
+
"--cov=gitlabber",
|
|
63
|
+
"--no-cov-on-fail",
|
|
64
|
+
"--cov-append",
|
|
65
|
+
"--cov-report=term-missing",
|
|
66
|
+
"--cov-report=xml",
|
|
67
|
+
"--verbose",
|
|
68
|
+
"--capture=sys",
|
|
69
|
+
"--without-slow-integration",
|
|
70
|
+
"--integration-cover"
|
|
71
|
+
]
|
|
72
|
+
norecursedirs = [
|
|
73
|
+
"dist",
|
|
74
|
+
"build"
|
|
75
|
+
]
|
|
76
|
+
testpaths = ["tests"]
|
|
77
|
+
|
|
78
|
+
[tool.coverage.run]
|
|
79
|
+
parallel = true
|
gitlabber-1.2.8/setup.py
ADDED
|
@@ -23,7 +23,7 @@ TREE_TEST_OUTPUT_FILE = "tests/test-output.tree"
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class MockNode:
|
|
26
|
-
def __init__(self, type, id, name, url, subgroups=mock.MagicMock(), projects=mock.MagicMock(), parent_id=None, archived=0, shared=False, group_search=None, git_options=None):
|
|
26
|
+
def __init__(self, type, id, name, url, subgroups=mock.MagicMock(), projects=mock.MagicMock(), shared_projects=mock.MagicMock(), parent_id=None, archived=0, shared=False, group_search=None, git_options=None):
|
|
27
27
|
self.type = type
|
|
28
28
|
self.id = id
|
|
29
29
|
self.name = name
|
|
@@ -34,6 +34,7 @@ class MockNode:
|
|
|
34
34
|
self.http_url_to_repo = url
|
|
35
35
|
self.subgroups = subgroups
|
|
36
36
|
self.projects = projects
|
|
37
|
+
self.shared_projects = shared_projects
|
|
37
38
|
self.parent_id = parent_id
|
|
38
39
|
self.archived = archived
|
|
39
40
|
self.shared = shared
|
|
@@ -119,9 +120,17 @@ def validate_tree(root):
|
|
|
119
120
|
validate_subgroup(root.children[0].children[0])
|
|
120
121
|
validate_project(root.children[0].children[0].children[0])
|
|
121
122
|
|
|
122
|
-
def create_test_gitlab(monkeypatch, includes=None, excludes=None, in_file=None, hide_token=True, method=CloneMethod.SSH):
|
|
123
|
+
def create_test_gitlab(monkeypatch, includes=None, excludes=None, in_file=None, hide_token=True, method=CloneMethod.SSH, token=TOKEN):
|
|
123
124
|
gl = gitlab_tree.GitlabTree(
|
|
124
|
-
URL,
|
|
125
|
+
URL,
|
|
126
|
+
token,
|
|
127
|
+
method, # Use the method parameter instead of hardcoding "ssh"
|
|
128
|
+
"name",
|
|
129
|
+
includes=includes,
|
|
130
|
+
excludes=excludes,
|
|
131
|
+
in_file=in_file,
|
|
132
|
+
hide_token=hide_token
|
|
133
|
+
)
|
|
125
134
|
projects = Listable(MockNode("project", 2, PROJECT_NAME, PROJECT_URL if hide_token else PROJECT_URL_WITH_TOKEN))
|
|
126
135
|
groups = Listable(
|
|
127
136
|
MockNode("group", 2, GROUP_NAME, GROUP_URL, subgroups=Listable(
|
|
@@ -131,7 +140,6 @@ def create_test_gitlab(monkeypatch, includes=None, excludes=None, in_file=None,
|
|
|
131
140
|
monkeypatch.setattr(gl.gitlab, "groups", Tree(groups))
|
|
132
141
|
return gl
|
|
133
142
|
|
|
134
|
-
|
|
135
143
|
def create_test_gitlab_with_toplevel_subgroups(monkeypatch):
|
|
136
144
|
gl = gitlab_tree.GitlabTree(URL, TOKEN, "ssh", "path")
|
|
137
145
|
groups = Listable(
|
|
@@ -167,9 +175,12 @@ def create_test_gitlab_with_shared(monkeypatch, includes=None, excludes=None, in
|
|
|
167
175
|
|
|
168
176
|
projects = Listable(
|
|
169
177
|
MockNode("project", 19, PROJECT_NAME, PROJECT_URL),
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
shared_projects = Listable(
|
|
170
181
|
MockNode("project", 20, "_shared_" + PROJECT_NAME, "_shared_" + PROJECT_URL, shared=True)
|
|
171
182
|
)
|
|
172
183
|
monkeypatch.setattr(gl.gitlab, "groups", Tree(Listable(
|
|
173
|
-
MockNode("group", 21, GROUP_NAME, GROUP_URL, projects=projects)
|
|
184
|
+
MockNode("group", 21, GROUP_NAME, GROUP_URL, projects=projects, shared_projects=shared_projects)
|
|
174
185
|
)))
|
|
175
186
|
return gl
|
|
@@ -11,7 +11,7 @@ coverage.process_startup()
|
|
|
11
11
|
@pytest.mark.slow_integration_test
|
|
12
12
|
def test_clone_subgroup():
|
|
13
13
|
os.environ['GITLAB_URL'] = 'https://gitlab.com/'
|
|
14
|
-
output = io_util.execute(['-p', '--print-format', 'json', '--group-search', 'Group Test'],
|
|
14
|
+
output = io_util.execute(['-p', '--print-format', 'json', '--group-search', 'Group Test'], 90)
|
|
15
15
|
obj = json.loads(output)
|
|
16
16
|
assert obj['children'][0]['name'] == 'Group Test'
|
|
17
17
|
assert obj['children'][0]['children'][0]['name'] == 'Subgroup Test'
|
|
@@ -23,7 +23,7 @@ def test_clone_subgroup():
|
|
|
23
23
|
@pytest.mark.slow_integration_test
|
|
24
24
|
def test_clone_subgroup_exclude_archived():
|
|
25
25
|
os.environ['GITLAB_URL'] = 'https://gitlab.com/'
|
|
26
|
-
output = io_util.execute(['-p', '--print-format', 'json', '--group-search', 'Group Test', '-a', 'exclude'],
|
|
26
|
+
output = io_util.execute(['-p', '--print-format', 'json', '--group-search', 'Group Test', '-a', 'exclude'], 90)
|
|
27
27
|
obj = json.loads(output)
|
|
28
28
|
assert obj['children'][0]['name'] == 'Group Test'
|
|
29
29
|
assert obj['children'][0]['children'][0]['name'] == 'Subgroup Test'
|
|
@@ -34,7 +34,7 @@ def test_clone_subgroup_exclude_archived():
|
|
|
34
34
|
@pytest.mark.slow_integration_test
|
|
35
35
|
def test_clone_subgroup_only_archived():
|
|
36
36
|
os.environ['GITLAB_URL'] = 'https://gitlab.com/'
|
|
37
|
-
output = io_util.execute(['-p', '--print-format', 'json', '--group-search', 'Group Test', '-a', 'only'],
|
|
37
|
+
output = io_util.execute(['-p', '--print-format', 'json', '--group-search', 'Group Test', '-a', 'only'], 90)
|
|
38
38
|
obj = json.loads(output)
|
|
39
39
|
assert obj['children'][0]['name'] == 'Group Test'
|
|
40
40
|
assert obj['children'][0]['children'][0]['name'] == 'Subgroup Test'
|
|
@@ -45,7 +45,7 @@ def test_clone_subgroup_only_archived():
|
|
|
45
45
|
@pytest.mark.slow_integration_test
|
|
46
46
|
def test_clone_subgroup_naming_path():
|
|
47
47
|
os.environ['GITLAB_URL'] = 'https://gitlab.com/'
|
|
48
|
-
output = io_util.execute(['-p', '--print-format', 'json', '-n', 'path', '--group-search', 'Group Test'],
|
|
48
|
+
output = io_util.execute(['-p', '--print-format', 'json', '-n', 'path', '--group-search', 'Group Test'], 90)
|
|
49
49
|
obj = json.loads(output)
|
|
50
50
|
assert obj['children'][0]['name'] == 'erez-group-test'
|
|
51
51
|
assert obj['children'][0]['children'][0]['name'] == 'subgroup-test'
|
|
@@ -58,7 +58,7 @@ def test_clone_subgroup_naming_path():
|
|
|
58
58
|
@pytest.mark.slow_integration_test
|
|
59
59
|
def test_large_groups():
|
|
60
60
|
os.environ['GITLAB_URL'] = 'https://gitlab.com/'
|
|
61
|
-
output = io_util.execute(['-p', '--print-format', 'json', '-n', 'path', '--group-search', 'large-group-test'],
|
|
61
|
+
output = io_util.execute(['-p', '--print-format', 'json', '-n', 'path', '--group-search', 'large-group-test'], 90)
|
|
62
62
|
obj = json.loads(output)
|
|
63
63
|
assert obj['children'][0]['name'] == 'large-group-test'
|
|
64
64
|
assert obj['children'][0]['children'][0]['name'] == 'many-subgroups'
|
|
@@ -70,8 +70,18 @@ def test_large_groups():
|
|
|
70
70
|
@pytest.mark.slow_integration_test
|
|
71
71
|
def test_user_personal_projects():
|
|
72
72
|
os.environ['GITLAB_URL'] = 'https://gitlab.com/'
|
|
73
|
-
output = io_util.execute(['-p', '--print-format', 'json', '-n', 'path', '--user-projects'],
|
|
73
|
+
output = io_util.execute(['-p', '--print-format', 'json', '-n', 'path', '--user-projects'], 90)
|
|
74
74
|
obj = json.loads(output)
|
|
75
75
|
assert obj['children'][0]['name'] == 'erezmazor-prsonal-projects'
|
|
76
76
|
assert obj['children'][0]['children'][0]['name'] == 'gitlabber-personal-project'
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@pytest.mark.slow_integration_test
|
|
80
|
+
def test_shared_group_and_project():
|
|
81
|
+
os.environ['GITLAB_URL'] = 'https://gitlab.com/'
|
|
82
|
+
output = io_util.execute(['-p', '--print-format', 'json', '-s', '--group-search', 'shared-group3'], 90)
|
|
83
|
+
obj = json.loads(output)
|
|
84
|
+
assert obj['children'][0]['name'] == 'Shared Group'
|
|
85
|
+
assert obj['children'][0]['children'][0]['name'] == 'Shared Project'
|
|
86
|
+
|
|
77
87
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
2
1
|
from gitlabber.method import CloneMethod
|
|
3
2
|
import tests.gitlab_test_utils as gitlab_util
|
|
4
3
|
import tests.io_test_util as output_util
|
|
5
4
|
from gitlabber.archive import ArchivedResults
|
|
5
|
+
import pytest
|
|
6
|
+
from unittest import mock
|
|
7
|
+
from gitlab.exceptions import GitlabGetError
|
|
6
8
|
|
|
7
9
|
def test_load_tree(monkeypatch):
|
|
8
10
|
gl = gitlab_util.create_test_gitlab(monkeypatch)
|
|
@@ -173,3 +175,73 @@ def test_hide_token_from_project_url(monkeypatch):
|
|
|
173
175
|
gl.load_tree()
|
|
174
176
|
gl.print_tree()
|
|
175
177
|
assert 'gitlab-token:xxx@' not in gl.root.children[0].children[0].children[0].url
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def test_get_subgroups_404_error(monkeypatch):
|
|
181
|
+
gl = gitlab_util.create_test_gitlab(monkeypatch)
|
|
182
|
+
|
|
183
|
+
# Create mock group and subgroup
|
|
184
|
+
mock_group = mock.Mock()
|
|
185
|
+
mock_group.name = "mock_group"
|
|
186
|
+
mock_group.id = 123
|
|
187
|
+
|
|
188
|
+
# Create a mock subgroup definition that will be returned by list()
|
|
189
|
+
mock_subgroup_def = mock.Mock()
|
|
190
|
+
mock_subgroup_def.id = 456
|
|
191
|
+
|
|
192
|
+
# Make subgroups.list return our mock subgroup definition
|
|
193
|
+
mock_group.subgroups.list.return_value = [mock_subgroup_def]
|
|
194
|
+
|
|
195
|
+
# This is the function that will raise the 404 when trying to get the subgroup
|
|
196
|
+
def mock_get_subgroup(id):
|
|
197
|
+
raise GitlabGetError(response_code=404, error_message="Not Found")
|
|
198
|
+
|
|
199
|
+
# Patch the groups.get method
|
|
200
|
+
monkeypatch.setattr(gl.gitlab.groups, "get", mock_get_subgroup)
|
|
201
|
+
|
|
202
|
+
with mock.patch("gitlabber.gitlab_tree.log.error") as mock_log_error:
|
|
203
|
+
gl.get_subgroups(mock_group, gl.root)
|
|
204
|
+
|
|
205
|
+
mock_log_error.assert_called_once_with(
|
|
206
|
+
f"404 error while getting subgroup with name: {mock_group.name} [id: {mock_group.id}]. Check your permissions as you may not have access to it. Message: Not Found"
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
def test_hide_token_in_project_url_both_cases(monkeypatch):
|
|
210
|
+
test_token = "test-token-123"
|
|
211
|
+
|
|
212
|
+
# Create two instances to test both cases
|
|
213
|
+
gl_hidden = gitlab_util.create_test_gitlab(monkeypatch,
|
|
214
|
+
hide_token=True,
|
|
215
|
+
method=CloneMethod.HTTP,
|
|
216
|
+
token=test_token)
|
|
217
|
+
|
|
218
|
+
gl_visible = gitlab_util.create_test_gitlab(monkeypatch,
|
|
219
|
+
hide_token=False,
|
|
220
|
+
method=CloneMethod.HTTP,
|
|
221
|
+
token=test_token)
|
|
222
|
+
|
|
223
|
+
# Create mock project
|
|
224
|
+
mock_project = mock.Mock()
|
|
225
|
+
mock_project.name = "test-project"
|
|
226
|
+
mock_project.path = "test-project"
|
|
227
|
+
mock_project.ssh_url_to_repo = "git@gitlab.com:group/test-project.git"
|
|
228
|
+
mock_project.http_url_to_repo = "https://gitlab.com/group/test-project.git"
|
|
229
|
+
|
|
230
|
+
# Test with hide_token=True
|
|
231
|
+
with mock.patch("gitlabber.gitlab_tree.log.debug") as mock_log_debug_hidden:
|
|
232
|
+
gl_hidden.add_projects(gl_hidden.root, [mock_project])
|
|
233
|
+
project_node_hidden = gl_hidden.root.children[0]
|
|
234
|
+
|
|
235
|
+
# Verify token is not in URL
|
|
236
|
+
assert project_node_hidden.url == "https://gitlab.com/group/test-project.git"
|
|
237
|
+
mock_log_debug_hidden.assert_any_call("Hiding token from project url: %s",
|
|
238
|
+
project_node_hidden.url)
|
|
239
|
+
|
|
240
|
+
# Test with hide_token=False
|
|
241
|
+
with mock.patch("gitlabber.gitlab_tree.log.debug") as mock_log_debug_visible:
|
|
242
|
+
gl_visible.add_projects(gl_visible.root, [mock_project])
|
|
243
|
+
project_node_visible = gl_visible.root.children[0]
|
|
244
|
+
|
|
245
|
+
expected_url = f"https://gitlab-token:{test_token}@gitlab.com/group/test-project.git"
|
|
246
|
+
assert project_node_visible.url == expected_url
|
|
247
|
+
mock_log_debug_visible.assert_any_call("Generated URL: %s", expected_url)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '1.2.6'
|
gitlabber-1.2.6/setup.cfg
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
[bdist_wheel]
|
|
2
|
-
universal = 1
|
|
3
|
-
|
|
4
|
-
[metadata]
|
|
5
|
-
description-file = README.rst
|
|
6
|
-
|
|
7
|
-
[coverage:run]
|
|
8
|
-
parallel = true
|
|
9
|
-
|
|
10
|
-
[tool:pytest]
|
|
11
|
-
addopts =
|
|
12
|
-
-vv --cov=gitlabber --no-cov-on-fail --cov-append --cov-report term-missing --cov-report xml --verbose --capture=sys --without-slow-integration --integration-cover
|
|
13
|
-
norecursedirs =
|
|
14
|
-
dist
|
|
15
|
-
build
|
|
16
|
-
|
|
17
|
-
[aliases]
|
|
18
|
-
dists = sdist bdist_wheel
|
|
19
|
-
testpaths = tests
|
|
20
|
-
|
|
21
|
-
[egg_info]
|
|
22
|
-
tag_build =
|
|
23
|
-
tag_date = 0
|
|
24
|
-
|
gitlabber-1.2.6/setup.py
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
"""Packaging settings."""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
from codecs import open
|
|
5
|
-
import os
|
|
6
|
-
from os.path import abspath, dirname, join
|
|
7
|
-
from subprocess import call
|
|
8
|
-
|
|
9
|
-
from setuptools import Command, find_packages, setup
|
|
10
|
-
|
|
11
|
-
from gitlabber import __version__
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
this_dir = abspath(dirname(__file__))
|
|
15
|
-
with open(join(this_dir, 'README.rst'), encoding='utf-8') as file:
|
|
16
|
-
long_description = file.read()
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class RunTests(Command):
|
|
20
|
-
"""Run all tests."""
|
|
21
|
-
description = 'run tests'
|
|
22
|
-
user_options = []
|
|
23
|
-
|
|
24
|
-
def initialize_options(self):
|
|
25
|
-
pass
|
|
26
|
-
|
|
27
|
-
def finalize_options(self):
|
|
28
|
-
pass
|
|
29
|
-
|
|
30
|
-
def run(self):
|
|
31
|
-
"""Run all tests!"""
|
|
32
|
-
errno = call(['py.test'])
|
|
33
|
-
raise SystemExit(errno)
|
|
34
|
-
setup(
|
|
35
|
-
python_requires='>=3',
|
|
36
|
-
name = 'gitlabber',
|
|
37
|
-
packages = ['gitlabber'],
|
|
38
|
-
version = __version__,
|
|
39
|
-
description = 'A Gitlab clone/pull utility for backing up or cloning Gitlab groups',
|
|
40
|
-
long_description = long_description,
|
|
41
|
-
long_description_content_type="text/x-rst",
|
|
42
|
-
url = 'https://github.com/ezbz/gitlabber',
|
|
43
|
-
download_url = 'https://github.com/ezbz/gitlabber/archive/main.zip',
|
|
44
|
-
author = 'Erez Mazor',
|
|
45
|
-
author_email = 'erezmazor@gmail.com',
|
|
46
|
-
license = 'MIT',
|
|
47
|
-
keywords = ['gitlab', 'python', 'cli'],
|
|
48
|
-
include_package_data = True,
|
|
49
|
-
|
|
50
|
-
classifiers = [
|
|
51
|
-
'Development Status :: 4 - Beta',
|
|
52
|
-
'Intended Audience :: Developers',
|
|
53
|
-
'Topic :: Utilities',
|
|
54
|
-
'License :: OSI Approved :: MIT License',
|
|
55
|
-
'Natural Language :: English',
|
|
56
|
-
'Operating System :: OS Independent',
|
|
57
|
-
'Programming Language :: Python :: 3',
|
|
58
|
-
'Programming Language :: Python :: 3.8',
|
|
59
|
-
'Programming Language :: Python :: 3.9',
|
|
60
|
-
'Programming Language :: Python :: 3.10',
|
|
61
|
-
'Programming Language :: Python :: 3.11',
|
|
62
|
-
'Programming Language :: Python :: 3.12'
|
|
63
|
-
],
|
|
64
|
-
setup_requires = [
|
|
65
|
-
'docopt',
|
|
66
|
-
'anytree',
|
|
67
|
-
'globre',
|
|
68
|
-
'pyyaml',
|
|
69
|
-
'tqdm',
|
|
70
|
-
'GitPython',
|
|
71
|
-
'python-gitlab'
|
|
72
|
-
],
|
|
73
|
-
install_requires = [
|
|
74
|
-
'docopt',
|
|
75
|
-
'anytree',
|
|
76
|
-
'globre',
|
|
77
|
-
'pyyaml',
|
|
78
|
-
'tqdm',
|
|
79
|
-
'GitPython',
|
|
80
|
-
'python-gitlab'
|
|
81
|
-
],
|
|
82
|
-
tests_require= ['coverage', 'pytest', 'pytest-cov', 'pytest-integration'],
|
|
83
|
-
entry_points = {
|
|
84
|
-
'console_scripts': [
|
|
85
|
-
'gitlabber=gitlabber.cli:main',
|
|
86
|
-
],
|
|
87
|
-
},
|
|
88
|
-
cmdclass = {'test': RunTests},
|
|
89
|
-
)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|