gitlabber 1.2.5.1__tar.gz → 1.2.7__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.5.1/gitlabber.egg-info → gitlabber-1.2.7}/PKG-INFO +34 -10
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/README.rst +16 -3
- gitlabber-1.2.7/gitlabber/__init__.py +2 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/cli.py +15 -3
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/git.py +6 -3
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/gitlab_tree.py +2 -1
- {gitlabber-1.2.5.1 → gitlabber-1.2.7/gitlabber.egg-info}/PKG-INFO +34 -10
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber.egg-info/SOURCES.txt +1 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber.egg-info/requires.txt +6 -0
- gitlabber-1.2.7/pyproject.toml +57 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/setup.cfg +1 -1
- gitlabber-1.2.7/setup.py +90 -0
- gitlabber-1.2.7/tests/__pycache__/gitlab_test_utils.cpython-311.pyc +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_cli.cpython-311-pytest-8.2.2.pyc +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_e2e.cpython-311-pytest-8.2.2.pyc +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_git.cpython-311-pytest-8.2.2.pyc +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_gitlab_tree.cpython-311-pytest-8.2.2.pyc +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_integration.cpython-311-pytest-8.2.2.pyc +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/gitlab_test_utils.py +6 -4
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_cli.py +5 -5
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_git.py +38 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_gitlab_tree.py +9 -1
- gitlabber-1.2.5.1/gitlabber/__init__.py +0 -1
- gitlabber-1.2.5.1/setup.py +0 -89
- gitlabber-1.2.5.1/tests/__pycache__/gitlab_test_utils.cpython-311.pyc +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/LICENSE.txt +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/MANIFEST.in +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/__main__.py +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/archive.py +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/format.py +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/method.py +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/naming.py +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/progress.py +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber.egg-info/dependency_links.txt +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber.egg-info/entry_points.txt +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber.egg-info/top_level.txt +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__init__.py +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/__init__.cpython-311.pyc +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/io_test_util.cpython-311.pyc +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_archive.cpython-311-pytest-8.2.2.pyc +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_format.cpython-311-pytest-8.2.2.pyc +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_method.cpython-311-pytest-8.2.2.pyc +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_naming.cpython-311-pytest-8.2.2.pyc +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/io_test_util.py +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test-input.yaml +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test-output.json +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test-output.tree +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test-output.yaml +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_archive.py +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_e2e.py +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_format.py +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_integration.py +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_method.py +0 -0
- {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_naming.py +0 -0
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: gitlabber
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.7
|
|
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,26 @@ 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"
|
|
26
37
|
|
|
27
38
|
.. image:: https://github.com/ezbz/gitlabber/actions/workflows/python-app.yml/badge.svg?branch=master
|
|
28
39
|
:target: https://github.com/ezbz/gitlabber/actions/workflows/python-app.yml
|
|
@@ -46,7 +57,7 @@ License-File: LICENSE.txt
|
|
|
46
57
|
Gitlabber
|
|
47
58
|
=========
|
|
48
59
|
|
|
49
|
-
* A utility to clone and pull GitLab groups, subgroups, projects based on path selection
|
|
60
|
+
* A utility to clone and pull GitLab groups, subgroups, group projects or personal user projects based on path selection
|
|
50
61
|
|
|
51
62
|
|
|
52
63
|
Purpose
|
|
@@ -104,7 +115,7 @@ Usage
|
|
|
104
115
|
|
|
105
116
|
* 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
117
|
|
|
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
|
|
118
|
+
* 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
119
|
|
|
109
120
|
* 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
121
|
|
|
@@ -115,7 +126,7 @@ Usage
|
|
|
115
126
|
.. code-block:: bash
|
|
116
127
|
|
|
117
128
|
usage: gitlabber [-h] [-t token] [-T] [-u url] [--verbose] [-p] [--print-format {json,yaml,tree}] [-n {name,path}] [-m {ssh,http}]
|
|
118
|
-
[-a {include,exclude,only}] [-i csv] [-x csv] [-r] [-F] [-d] [-s] [-g term] [-U] [--version]
|
|
129
|
+
[-a {include,exclude,only}] [-i csv] [-x csv] [-r] [-F] [-d] [-s] [-g term] [-U] [-o options] [--version]
|
|
119
130
|
[dest]
|
|
120
131
|
|
|
121
132
|
Gitlabber - clones or pulls entire groups/projects tree from gitlab
|
|
@@ -150,6 +161,8 @@ Usage
|
|
|
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)
|
|
152
163
|
-U, --user-projects fetch only user personal projects (skips the group tree altogether, group related parameters are ignored). Clones personal projects to '{gitlab-username}-personal-projects'
|
|
164
|
+
-o options, --git-options options
|
|
165
|
+
provide additional options as csv for the git command (e.g., --depth=1). See: clone/multi_options https://gitpython.readthedocs.io/en/stable/reference.html#
|
|
153
166
|
--version print the version
|
|
154
167
|
|
|
155
168
|
examples:
|
|
@@ -172,6 +185,12 @@ Usage
|
|
|
172
185
|
clone projects that start with a case insensitive 'w' using a regular expression:
|
|
173
186
|
gitlabber -i '/{[w].*}' .
|
|
174
187
|
|
|
188
|
+
clone a user's personal projects to username-personal-projects
|
|
189
|
+
gitlabber -U .
|
|
190
|
+
|
|
191
|
+
perform a shallow clone of the git repositories
|
|
192
|
+
gitlabber -o "\-\-depth=1," .
|
|
193
|
+
|
|
175
194
|
|
|
176
195
|
|
|
177
196
|
Debugging
|
|
@@ -193,3 +212,8 @@ Known Limitations
|
|
|
193
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.
|
|
194
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).
|
|
195
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
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
Gitlabber
|
|
21
21
|
=========
|
|
22
22
|
|
|
23
|
-
* A utility to clone and pull GitLab groups, subgroups, projects based on path selection
|
|
23
|
+
* A utility to clone and pull GitLab groups, subgroups, group projects or personal user projects based on path selection
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
Purpose
|
|
@@ -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
|
|
|
@@ -89,7 +89,7 @@ Usage
|
|
|
89
89
|
.. code-block:: bash
|
|
90
90
|
|
|
91
91
|
usage: gitlabber [-h] [-t token] [-T] [-u url] [--verbose] [-p] [--print-format {json,yaml,tree}] [-n {name,path}] [-m {ssh,http}]
|
|
92
|
-
[-a {include,exclude,only}] [-i csv] [-x csv] [-r] [-F] [-d] [-s] [-g term] [-U] [--version]
|
|
92
|
+
[-a {include,exclude,only}] [-i csv] [-x csv] [-r] [-F] [-d] [-s] [-g term] [-U] [-o options] [--version]
|
|
93
93
|
[dest]
|
|
94
94
|
|
|
95
95
|
Gitlabber - clones or pulls entire groups/projects tree from gitlab
|
|
@@ -124,6 +124,8 @@ Usage
|
|
|
124
124
|
-g term, --group-search term
|
|
125
125
|
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)
|
|
126
126
|
-U, --user-projects fetch only user personal projects (skips the group tree altogether, group related parameters are ignored). Clones personal projects to '{gitlab-username}-personal-projects'
|
|
127
|
+
-o options, --git-options options
|
|
128
|
+
provide additional options as csv for the git command (e.g., --depth=1). See: clone/multi_options https://gitpython.readthedocs.io/en/stable/reference.html#
|
|
127
129
|
--version print the version
|
|
128
130
|
|
|
129
131
|
examples:
|
|
@@ -146,6 +148,12 @@ Usage
|
|
|
146
148
|
clone projects that start with a case insensitive 'w' using a regular expression:
|
|
147
149
|
gitlabber -i '/{[w].*}' .
|
|
148
150
|
|
|
151
|
+
clone a user's personal projects to username-personal-projects
|
|
152
|
+
gitlabber -U .
|
|
153
|
+
|
|
154
|
+
perform a shallow clone of the git repositories
|
|
155
|
+
gitlabber -o "\-\-depth=1," .
|
|
156
|
+
|
|
149
157
|
|
|
150
158
|
|
|
151
159
|
Debugging
|
|
@@ -167,3 +175,8 @@ Known Limitations
|
|
|
167
175
|
* 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.
|
|
168
176
|
* 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).
|
|
169
177
|
* 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>`_.
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
Links
|
|
181
|
+
-----
|
|
182
|
+
* 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
|
|
@@ -43,7 +42,8 @@ def main():
|
|
|
43
42
|
|
|
44
43
|
tree = GitlabTree(args.url, args.token, args.method, args.naming, args.archived.api_value, includes,
|
|
45
44
|
excludes, args.file, args.concurrency, args.recursive, args.verbose,
|
|
46
|
-
args.include_shared, args.use_fetch, args.hide_token, args.user_projects,
|
|
45
|
+
args.include_shared, args.use_fetch, args.hide_token, args.user_projects,
|
|
46
|
+
group_search=args.group_search, git_options=args.git_options)
|
|
47
47
|
tree.load_tree()
|
|
48
48
|
|
|
49
49
|
if tree.is_empty():
|
|
@@ -72,7 +72,7 @@ def config_logging(args):
|
|
|
72
72
|
|
|
73
73
|
|
|
74
74
|
def parse_args(argv=None):
|
|
75
|
-
example_text = '''examples:
|
|
75
|
+
example_text = r'''examples:
|
|
76
76
|
|
|
77
77
|
clone an entire gitlab tree using a url and a token:
|
|
78
78
|
gitlabber -t <personal access token> -u <gitlab url>
|
|
@@ -91,6 +91,12 @@ def parse_args(argv=None):
|
|
|
91
91
|
|
|
92
92
|
clone projects that start with a case insensitive 'w' using a regular expression:
|
|
93
93
|
gitlabber -i '/{[w].*}' .
|
|
94
|
+
|
|
95
|
+
clone a user's personal projects to username-personal-projects
|
|
96
|
+
gitlabber -U .
|
|
97
|
+
|
|
98
|
+
perform a shallow clone of the git repositories
|
|
99
|
+
gitlabber -o "\-\-depth=1," .
|
|
94
100
|
'''
|
|
95
101
|
|
|
96
102
|
parser = ArgumentParser(
|
|
@@ -216,6 +222,12 @@ def parse_args(argv=None):
|
|
|
216
222
|
action='store_true',
|
|
217
223
|
default=False,
|
|
218
224
|
help='fetch only user personal projects (skips the group tree altogether, group related parameters are ignored). Clones personal projects to \'{gitlab-username}-personal-projects\'')
|
|
225
|
+
parser.add_argument(
|
|
226
|
+
'-o',
|
|
227
|
+
'--git-options',
|
|
228
|
+
nargs=1,
|
|
229
|
+
metavar=('options'),
|
|
230
|
+
help='provide additional options as csv for the git command (e.g., --depth=1). See: clone/multi_options https://gitpython.readthedocs.io/en/stable/reference.html#')
|
|
219
231
|
parser.add_argument(
|
|
220
232
|
'--version',
|
|
221
233
|
action='store_true',
|
|
@@ -12,14 +12,15 @@ progress = ProgressBar('* syncing projects')
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class GitAction:
|
|
15
|
-
def __init__(self, node, path, recursive=False, use_fetch=False, hide_token=False):
|
|
15
|
+
def __init__(self, node, path, recursive=False, use_fetch=False, hide_token=False, git_options=None):
|
|
16
16
|
self.node = node
|
|
17
17
|
self.path = path
|
|
18
18
|
self.recursive = recursive
|
|
19
19
|
self.use_fetch = use_fetch
|
|
20
20
|
self.hide_token = hide_token
|
|
21
|
+
self.git_options = git_options
|
|
21
22
|
|
|
22
|
-
def sync_tree(root, dest, concurrency=1, disable_progress=False, recursive=False, use_fetch=False, hide_token=False):
|
|
23
|
+
def sync_tree(root, dest, concurrency=1, disable_progress=False, recursive=False, use_fetch=False, hide_token=False, git_options=None):
|
|
23
24
|
if not disable_progress:
|
|
24
25
|
progress.init_progress(len(root.leaves))
|
|
25
26
|
actions = get_git_actions(root, dest, recursive, use_fetch, hide_token)
|
|
@@ -71,7 +72,7 @@ def clone_or_pull_project(action):
|
|
|
71
72
|
log.fatal("User interrupted")
|
|
72
73
|
sys.exit(0)
|
|
73
74
|
except Exception as e:
|
|
74
|
-
log.
|
|
75
|
+
log.error("Error pulling project %s", action.path, exc_info=True)
|
|
75
76
|
else:
|
|
76
77
|
'''
|
|
77
78
|
Clone new project
|
|
@@ -86,6 +87,8 @@ def clone_or_pull_project(action):
|
|
|
86
87
|
multi_options.append('--recursive')
|
|
87
88
|
if(action.use_fetch):
|
|
88
89
|
multi_options.append('--mirror')
|
|
90
|
+
if(action.git_options):
|
|
91
|
+
multi_options += action.git_options.split(',')
|
|
89
92
|
try:
|
|
90
93
|
git.Repo.clone_from(action.node.url, action.path, multi_options=multi_options)
|
|
91
94
|
|
|
@@ -18,7 +18,7 @@ log = logging.getLogger(__name__)
|
|
|
18
18
|
|
|
19
19
|
class GitlabTree:
|
|
20
20
|
def __init__(self, url, token, method, naming=None, archived=None, includes=[], excludes=[], in_file=None, concurrency=1, recursive=False, disable_progress=False,
|
|
21
|
-
include_shared=True, use_fetch=False, hide_token=False, user_projects=False, group_search=None):
|
|
21
|
+
include_shared=True, use_fetch=False, hide_token=False, user_projects=False, group_search=None, git_options=None):
|
|
22
22
|
self.includes = includes
|
|
23
23
|
self.excludes = excludes
|
|
24
24
|
self.url = url
|
|
@@ -39,6 +39,7 @@ class GitlabTree:
|
|
|
39
39
|
self.hide_token = hide_token
|
|
40
40
|
self.user_projects = user_projects
|
|
41
41
|
self.group_search = group_search
|
|
42
|
+
self.git_options = git_options
|
|
42
43
|
|
|
43
44
|
@staticmethod
|
|
44
45
|
def get_ca_path():
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: gitlabber
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.7
|
|
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,26 @@ 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"
|
|
26
37
|
|
|
27
38
|
.. image:: https://github.com/ezbz/gitlabber/actions/workflows/python-app.yml/badge.svg?branch=master
|
|
28
39
|
:target: https://github.com/ezbz/gitlabber/actions/workflows/python-app.yml
|
|
@@ -46,7 +57,7 @@ License-File: LICENSE.txt
|
|
|
46
57
|
Gitlabber
|
|
47
58
|
=========
|
|
48
59
|
|
|
49
|
-
* A utility to clone and pull GitLab groups, subgroups, projects based on path selection
|
|
60
|
+
* A utility to clone and pull GitLab groups, subgroups, group projects or personal user projects based on path selection
|
|
50
61
|
|
|
51
62
|
|
|
52
63
|
Purpose
|
|
@@ -104,7 +115,7 @@ Usage
|
|
|
104
115
|
|
|
105
116
|
* 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
117
|
|
|
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
|
|
118
|
+
* 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
119
|
|
|
109
120
|
* 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
121
|
|
|
@@ -115,7 +126,7 @@ Usage
|
|
|
115
126
|
.. code-block:: bash
|
|
116
127
|
|
|
117
128
|
usage: gitlabber [-h] [-t token] [-T] [-u url] [--verbose] [-p] [--print-format {json,yaml,tree}] [-n {name,path}] [-m {ssh,http}]
|
|
118
|
-
[-a {include,exclude,only}] [-i csv] [-x csv] [-r] [-F] [-d] [-s] [-g term] [-U] [--version]
|
|
129
|
+
[-a {include,exclude,only}] [-i csv] [-x csv] [-r] [-F] [-d] [-s] [-g term] [-U] [-o options] [--version]
|
|
119
130
|
[dest]
|
|
120
131
|
|
|
121
132
|
Gitlabber - clones or pulls entire groups/projects tree from gitlab
|
|
@@ -150,6 +161,8 @@ Usage
|
|
|
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)
|
|
152
163
|
-U, --user-projects fetch only user personal projects (skips the group tree altogether, group related parameters are ignored). Clones personal projects to '{gitlab-username}-personal-projects'
|
|
164
|
+
-o options, --git-options options
|
|
165
|
+
provide additional options as csv for the git command (e.g., --depth=1). See: clone/multi_options https://gitpython.readthedocs.io/en/stable/reference.html#
|
|
153
166
|
--version print the version
|
|
154
167
|
|
|
155
168
|
examples:
|
|
@@ -172,6 +185,12 @@ Usage
|
|
|
172
185
|
clone projects that start with a case insensitive 'w' using a regular expression:
|
|
173
186
|
gitlabber -i '/{[w].*}' .
|
|
174
187
|
|
|
188
|
+
clone a user's personal projects to username-personal-projects
|
|
189
|
+
gitlabber -U .
|
|
190
|
+
|
|
191
|
+
perform a shallow clone of the git repositories
|
|
192
|
+
gitlabber -o "\-\-depth=1," .
|
|
193
|
+
|
|
175
194
|
|
|
176
195
|
|
|
177
196
|
Debugging
|
|
@@ -193,3 +212,8 @@ Known Limitations
|
|
|
193
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.
|
|
194
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).
|
|
195
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
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=45", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "gitlabber"
|
|
7
|
+
version = "1.2.7"
|
|
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
|
gitlabber-1.2.7/setup.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
|
|
3
|
+
setup()
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# """Packaging settings."""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# from codecs import open
|
|
10
|
+
# from os.path import abspath, dirname, join
|
|
11
|
+
# from subprocess import call
|
|
12
|
+
|
|
13
|
+
# from setuptools import Command, find_packages, setup
|
|
14
|
+
|
|
15
|
+
# this_dir = abspath(dirname(__file__))
|
|
16
|
+
# with open(join(this_dir, 'README.rst'), encoding='utf-8') as file:
|
|
17
|
+
# long_description = file.read()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# class RunTests(Command):
|
|
21
|
+
# """Run all tests."""
|
|
22
|
+
# description = 'run tests'
|
|
23
|
+
# user_options = []
|
|
24
|
+
|
|
25
|
+
# def initialize_options(self):
|
|
26
|
+
# pass
|
|
27
|
+
|
|
28
|
+
# def finalize_options(self):
|
|
29
|
+
# pass
|
|
30
|
+
|
|
31
|
+
# def run(self):
|
|
32
|
+
# """Run all tests!"""
|
|
33
|
+
# errno = call(['py.test'])
|
|
34
|
+
# raise SystemExit(errno)
|
|
35
|
+
# setup(
|
|
36
|
+
# python_requires='>=3',
|
|
37
|
+
# name = 'gitlabber',
|
|
38
|
+
# packages = find_packages(include=['gitlabber']),
|
|
39
|
+
# version = '1.2.7',
|
|
40
|
+
# description = 'A Gitlab clone/pull utility for backing up or cloning Gitlab groups',
|
|
41
|
+
# long_description = long_description,
|
|
42
|
+
# long_description_content_type="text/x-rst",
|
|
43
|
+
# url = 'https://github.com/ezbz/gitlabber',
|
|
44
|
+
# download_url = 'https://github.com/ezbz/gitlabber/archive/main.zip',
|
|
45
|
+
# author = 'Erez Mazor',
|
|
46
|
+
# author_email = 'erezmazor@gmail.com',
|
|
47
|
+
# license = 'MIT',
|
|
48
|
+
# keywords = ['gitlab', 'python', 'cli'],
|
|
49
|
+
# include_package_data = True,
|
|
50
|
+
|
|
51
|
+
# classifiers = [
|
|
52
|
+
# 'Development Status :: 4 - Beta',
|
|
53
|
+
# 'Intended Audience :: Developers',
|
|
54
|
+
# 'Topic :: Utilities',
|
|
55
|
+
# 'License :: OSI Approved :: MIT License',
|
|
56
|
+
# 'Natural Language :: English',
|
|
57
|
+
# 'Operating System :: OS Independent',
|
|
58
|
+
# 'Programming Language :: Python :: 3',
|
|
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
|
+
# 'Programming Language :: Python :: 3.13'
|
|
64
|
+
# ],
|
|
65
|
+
# setup_requires = [
|
|
66
|
+
# 'docopt',
|
|
67
|
+
# 'anytree',
|
|
68
|
+
# 'globre',
|
|
69
|
+
# 'pyyaml',
|
|
70
|
+
# 'tqdm',
|
|
71
|
+
# 'GitPython',
|
|
72
|
+
# 'python-gitlab'
|
|
73
|
+
# ],
|
|
74
|
+
# install_requires = [
|
|
75
|
+
# 'docopt',
|
|
76
|
+
# 'anytree',
|
|
77
|
+
# 'globre',
|
|
78
|
+
# 'pyyaml',
|
|
79
|
+
# 'tqdm',
|
|
80
|
+
# 'GitPython',
|
|
81
|
+
# 'python-gitlab'
|
|
82
|
+
# ],
|
|
83
|
+
# tests_require= ['coverage', 'pytest', 'pytest-cov', 'pytest-integration'],
|
|
84
|
+
# entry_points = {
|
|
85
|
+
# 'console_scripts': [
|
|
86
|
+
# 'gitlabber=gitlabber.cli:main',
|
|
87
|
+
# ],
|
|
88
|
+
# },
|
|
89
|
+
# cmdclass = {'test': RunTests},
|
|
90
|
+
# )
|
|
Binary file
|
{gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_cli.cpython-311-pytest-8.2.2.pyc
RENAMED
|
Binary file
|
{gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_e2e.cpython-311-pytest-8.2.2.pyc
RENAMED
|
Binary file
|
{gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_git.cpython-311-pytest-8.2.2.pyc
RENAMED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -2,6 +2,7 @@ import pytest
|
|
|
2
2
|
import json
|
|
3
3
|
from unittest import mock
|
|
4
4
|
from gitlabber import gitlab_tree
|
|
5
|
+
from gitlabber.method import CloneMethod
|
|
5
6
|
|
|
6
7
|
URL = "http://gitlab.my.com/"
|
|
7
8
|
TOKEN = "MOCK_TOKEN"
|
|
@@ -12,6 +13,7 @@ SUBGROUP_URL = "http://gitlab.my.com/group/subgroup"
|
|
|
12
13
|
SUBGROUP_NAME = "subgroup"
|
|
13
14
|
|
|
14
15
|
PROJECT_URL = "http://gitlab.my.com/group/subgroup/project/project.git"
|
|
16
|
+
PROJECT_URL_WITH_TOKEN = "http://gitlab-token:xxx@gitlab.my.com/group/subgroup/project/project.git"
|
|
15
17
|
PROJECT_NAME = "project"
|
|
16
18
|
|
|
17
19
|
YAML_TEST_INPUT_FILE = "tests/test-input.yaml"
|
|
@@ -21,7 +23,7 @@ TREE_TEST_OUTPUT_FILE = "tests/test-output.tree"
|
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
class MockNode:
|
|
24
|
-
def __init__(self, type, id, name, url, subgroups=mock.MagicMock(), projects=mock.MagicMock(), parent_id=None, archived=0, shared=False, group_search=None):
|
|
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):
|
|
25
27
|
self.type = type
|
|
26
28
|
self.id = id
|
|
27
29
|
self.name = name
|
|
@@ -117,10 +119,10 @@ def validate_tree(root):
|
|
|
117
119
|
validate_subgroup(root.children[0].children[0])
|
|
118
120
|
validate_project(root.children[0].children[0].children[0])
|
|
119
121
|
|
|
120
|
-
def create_test_gitlab(monkeypatch, includes=None, excludes=None, in_file=None):
|
|
122
|
+
def create_test_gitlab(monkeypatch, includes=None, excludes=None, in_file=None, hide_token=True, method=CloneMethod.SSH):
|
|
121
123
|
gl = gitlab_tree.GitlabTree(
|
|
122
|
-
URL, TOKEN, "ssh", "name", includes=includes, excludes=excludes, in_file=in_file)
|
|
123
|
-
projects = Listable(MockNode("project", 2, PROJECT_NAME, PROJECT_URL))
|
|
124
|
+
URL, TOKEN, "ssh", "name", includes=includes, excludes=excludes, in_file=in_file, hide_token=hide_token)
|
|
125
|
+
projects = Listable(MockNode("project", 2, PROJECT_NAME, PROJECT_URL if hide_token else PROJECT_URL_WITH_TOKEN))
|
|
124
126
|
groups = Listable(
|
|
125
127
|
MockNode("group", 2, GROUP_NAME, GROUP_URL, subgroups=Listable(
|
|
126
128
|
MockNode("subgroup", 3, SUBGROUP_NAME, SUBGROUP_URL, projects=projects)
|
|
@@ -36,7 +36,7 @@ def test_args_version():
|
|
|
36
36
|
def test_args_logging(mock_tree, mock_log, mock_os, mock_sys, mock_logging):
|
|
37
37
|
args_mock = mock.Mock()
|
|
38
38
|
args_mock.return_value = Node(
|
|
39
|
-
type="test", name="test", version=None, verbose=True, include="", exclude="", url="test_url", token="test_token", method=CloneMethod.SSH, naming=FolderNaming.PATH, archived=ArchivedResults.INCLUDE, file=None, concurrency=1, recursive=False, disble_progress=True, print=None, dest=".", include_shared=True, use_fetch=None, hide_token=None, user_projects=None, group_search=None)
|
|
39
|
+
type="test", name="test", version=None, verbose=True, include="", exclude="", url="test_url", token="test_token", method=CloneMethod.SSH, naming=FolderNaming.PATH, archived=ArchivedResults.INCLUDE, file=None, concurrency=1, recursive=False, disble_progress=True, print=None, dest=".", include_shared=True, use_fetch=None, hide_token=None, user_projects=None, group_search=None, git_options=None)
|
|
40
40
|
cli.parse_args = args_mock
|
|
41
41
|
|
|
42
42
|
mock_streamhandler = mock.Mock()
|
|
@@ -57,7 +57,7 @@ def test_args_include(mock_tree):
|
|
|
57
57
|
exc_groups = "/exc**,/exc**"
|
|
58
58
|
args_mock = mock.Mock()
|
|
59
59
|
args_mock.return_value = Node(
|
|
60
|
-
type="test", name="test", version=None, debug=None, include=inc_groups, exclude=exc_groups, url="test_url", token="test_token", method=CloneMethod.SSH, naming=FolderNaming.NAME, archived=ArchivedResults.INCLUDE, file=None, concurrency=1, recursive=False, disble_progress=True, print=None, dest=".", use_fetch=None, hide_token=None, user_projects=None, group_search=None)
|
|
60
|
+
type="test", name="test", version=None, debug=None, include=inc_groups, exclude=exc_groups, url="test_url", token="test_token", method=CloneMethod.SSH, naming=FolderNaming.NAME, archived=ArchivedResults.INCLUDE, file=None, concurrency=1, recursive=False, disble_progress=True, print=None, dest=".", use_fetch=None, hide_token=None, user_projects=None, group_search=None, git_options=None)
|
|
61
61
|
cli.parse_args = args_mock
|
|
62
62
|
|
|
63
63
|
split_mock = mock.Mock()
|
|
@@ -73,7 +73,7 @@ def test_args_include(mock_tree):
|
|
|
73
73
|
def test_args_include(mock_tree):
|
|
74
74
|
args_mock = mock.Mock()
|
|
75
75
|
args_mock.return_value = Node(
|
|
76
|
-
type="test", name="test", version=None, verbose=None, include="", exclude="", url="test_url", token="test_token", method=CloneMethod.SSH, naming=FolderNaming.NAME, archived=ArchivedResults.INCLUDE, file=None, concurrency=1, recursive=False, disble_progress=True, print=True, dest=".", print_format=PrintFormat.YAML, include_shared=True, use_fetch=None, hide_token=None, user_projects=None, group_search=None)
|
|
76
|
+
type="test", name="test", version=None, verbose=None, include="", exclude="", url="test_url", token="test_token", method=CloneMethod.SSH, naming=FolderNaming.NAME, archived=ArchivedResults.INCLUDE, file=None, concurrency=1, recursive=False, disble_progress=True, print=True, dest=".", print_format=PrintFormat.YAML, include_shared=True, use_fetch=None, hide_token=None, user_projects=None, group_search=None, git_options=None)
|
|
77
77
|
cli.parse_args = args_mock
|
|
78
78
|
|
|
79
79
|
print_tree_mock = mock.Mock()
|
|
@@ -116,7 +116,7 @@ def test_missing_url(mock_tree):
|
|
|
116
116
|
def test_empty_tree(mock_tree):
|
|
117
117
|
args_mock = mock.Mock()
|
|
118
118
|
args_mock.return_value = Node(
|
|
119
|
-
type="test", name="test", version=None, verbose=None, include="", exclude="", url="test_url", token="test_token", method=CloneMethod.SSH, naming=FolderNaming.NAME, archived=ArchivedResults.INCLUDE, file=None, concurrency=1, recursive=False, disble_progress=True, print=True, dest=".", include_shared=True, use_fetch=None, hide_token=None, user_projects=None, group_search=None)
|
|
119
|
+
type="test", name="test", version=None, verbose=None, include="", exclude="", url="test_url", token="test_token", method=CloneMethod.SSH, naming=FolderNaming.NAME, archived=ArchivedResults.INCLUDE, file=None, concurrency=1, recursive=False, disble_progress=True, print=True, dest=".", include_shared=True, use_fetch=None, hide_token=None, user_projects=None, group_search=None, git_options=None)
|
|
120
120
|
cli.parse_args = args_mock
|
|
121
121
|
|
|
122
122
|
with pytest.raises(SystemExit):
|
|
@@ -127,7 +127,7 @@ def test_empty_tree(mock_tree):
|
|
|
127
127
|
def test_missing_dest(mock_tree, capsys):
|
|
128
128
|
args_mock = mock.Mock()
|
|
129
129
|
args_mock.return_value = Node(
|
|
130
|
-
type="test", name="test", version=None, verbose=None, include="", exclude="", url="test_url", token="test_token", method=CloneMethod.SSH, naming=FolderNaming.NAME, archived=ArchivedResults.INCLUDE, file=None, concurrency=1, recursive=False, disble_progress=True, print=False, dest=None, group_search=None)
|
|
130
|
+
type="test", name="test", version=None, verbose=None, include="", exclude="", url="test_url", token="test_token", method=CloneMethod.SSH, naming=FolderNaming.NAME, archived=ArchivedResults.INCLUDE, file=None, concurrency=1, recursive=False, disble_progress=True, print=False, dest=None, group_search=None, git_options=None)
|
|
131
131
|
cli.parse_args = args_mock
|
|
132
132
|
mock_tree.return_value.is_empty = mock.Mock(return_value=False)
|
|
133
133
|
|
|
@@ -115,6 +115,20 @@ def test_pull_repo_exception(mock_git):
|
|
|
115
115
|
|
|
116
116
|
mock_git.Repo.assert_called_once_with("dummy_dir")
|
|
117
117
|
repo_instance.remotes.origin.pull.assert_called_once()
|
|
118
|
+
|
|
119
|
+
@mock.patch('gitlabber.git.git')
|
|
120
|
+
def test_clone_repo_exception(mock_git):
|
|
121
|
+
mock_repo = mock.Mock()
|
|
122
|
+
mock_git.Repo = mock_repo
|
|
123
|
+
git.is_git_repo = mock.MagicMock(return_value=False)
|
|
124
|
+
|
|
125
|
+
repo_instance = mock_git.Repo.return_value
|
|
126
|
+
repo_instance.clone_from.side_effect=Exception('clone test exception')
|
|
127
|
+
|
|
128
|
+
git.clone_or_pull_project(
|
|
129
|
+
GitAction(Node(type="project", name="dummy_url", url="dummy_url"), "dummy_dir"))
|
|
130
|
+
mock_git.Repo.clone_from.assert_called_once_with('dummy_url', 'dummy_dir', multi_options=[])
|
|
131
|
+
mock_git.Repo.clone_from.assert_called_once()
|
|
118
132
|
|
|
119
133
|
@mock.patch('gitlabber.git.git')
|
|
120
134
|
def test_pull_repo_interrupt(mock_git):
|
|
@@ -144,3 +158,27 @@ def test_clone_repo_interrupt(mock_git):
|
|
|
144
158
|
Node(type="project", name="dummy_url", url="dummy_url"), "dummy_dir"))
|
|
145
159
|
|
|
146
160
|
mock_git.Repo.clone_from.assert_called_once_with("dummy_url", "dummy_dir", multi_options=[])
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
@mock.patch('gitlabber.git.git')
|
|
164
|
+
def test_clone_repo_options_many_options(mock_git):
|
|
165
|
+
mock_repo = mock.Mock()
|
|
166
|
+
mock_git.Repo = mock_repo
|
|
167
|
+
git.is_git_repo = mock.MagicMock(return_value=False)
|
|
168
|
+
|
|
169
|
+
git.clone_or_pull_project(
|
|
170
|
+
GitAction(Node(type="project", name="dummy_url", url="dummy_url"), "dummy_dir", git_options="--opt1=1,--opt2=2"))
|
|
171
|
+
|
|
172
|
+
mock_git.Repo.clone_from.assert_called_once_with("dummy_url", "dummy_dir", multi_options=['--opt1=1','--opt2=2'])
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@mock.patch('gitlabber.git.git')
|
|
176
|
+
def test_clone_repo_options_with_recursive(mock_git):
|
|
177
|
+
mock_repo = mock.Mock()
|
|
178
|
+
mock_git.Repo = mock_repo
|
|
179
|
+
git.is_git_repo = mock.MagicMock(return_value=False)
|
|
180
|
+
|
|
181
|
+
git.clone_or_pull_project(
|
|
182
|
+
GitAction(Node(type="project", name="dummy_url", url="dummy_url"), "dummy_dir", recursive=True, git_options="--opt1=1,--opt2=2"))
|
|
183
|
+
|
|
184
|
+
mock_git.Repo.clone_from.assert_called_once_with("dummy_url", "dummy_dir", multi_options=['--recursive','--opt1=1','--opt2=2'])
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
|
|
2
|
+
from gitlabber.method import CloneMethod
|
|
2
3
|
import tests.gitlab_test_utils as gitlab_util
|
|
3
4
|
import tests.io_test_util as output_util
|
|
4
5
|
from gitlabber.archive import ArchivedResults
|
|
@@ -164,4 +165,11 @@ def test_shared_excluded(monkeypatch):
|
|
|
164
165
|
assert len(gl.root.children) == 1
|
|
165
166
|
assert len(gl.root.children[0].children) == 1
|
|
166
167
|
|
|
167
|
-
assert "project" in gl.root.children[0].children[0].name
|
|
168
|
+
assert "project" in gl.root.children[0].children[0].name
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def test_hide_token_from_project_url(monkeypatch):
|
|
172
|
+
gl = gitlab_util.create_test_gitlab(monkeypatch, hide_token=True, method=CloneMethod.HTTP)
|
|
173
|
+
gl.load_tree()
|
|
174
|
+
gl.print_tree()
|
|
175
|
+
assert 'gitlab-token:xxx@' not in gl.root.children[0].children[0].children[0].url
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '1.2.5.1'
|
gitlabber-1.2.5.1/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
|
|
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
|
{gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_archive.cpython-311-pytest-8.2.2.pyc
RENAMED
|
File without changes
|
{gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_format.cpython-311-pytest-8.2.2.pyc
RENAMED
|
File without changes
|
{gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_method.cpython-311-pytest-8.2.2.pyc
RENAMED
|
File without changes
|
{gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_naming.cpython-311-pytest-8.2.2.pyc
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|