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.
Files changed (54) hide show
  1. {gitlabber-1.2.5.1/gitlabber.egg-info → gitlabber-1.2.7}/PKG-INFO +34 -10
  2. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/README.rst +16 -3
  3. gitlabber-1.2.7/gitlabber/__init__.py +2 -0
  4. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/cli.py +15 -3
  5. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/git.py +6 -3
  6. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/gitlab_tree.py +2 -1
  7. {gitlabber-1.2.5.1 → gitlabber-1.2.7/gitlabber.egg-info}/PKG-INFO +34 -10
  8. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber.egg-info/SOURCES.txt +1 -0
  9. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber.egg-info/requires.txt +6 -0
  10. gitlabber-1.2.7/pyproject.toml +57 -0
  11. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/setup.cfg +1 -1
  12. gitlabber-1.2.7/setup.py +90 -0
  13. gitlabber-1.2.7/tests/__pycache__/gitlab_test_utils.cpython-311.pyc +0 -0
  14. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_cli.cpython-311-pytest-8.2.2.pyc +0 -0
  15. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_e2e.cpython-311-pytest-8.2.2.pyc +0 -0
  16. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_git.cpython-311-pytest-8.2.2.pyc +0 -0
  17. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_gitlab_tree.cpython-311-pytest-8.2.2.pyc +0 -0
  18. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_integration.cpython-311-pytest-8.2.2.pyc +0 -0
  19. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/gitlab_test_utils.py +6 -4
  20. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_cli.py +5 -5
  21. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_git.py +38 -0
  22. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_gitlab_tree.py +9 -1
  23. gitlabber-1.2.5.1/gitlabber/__init__.py +0 -1
  24. gitlabber-1.2.5.1/setup.py +0 -89
  25. gitlabber-1.2.5.1/tests/__pycache__/gitlab_test_utils.cpython-311.pyc +0 -0
  26. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/LICENSE.txt +0 -0
  27. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/MANIFEST.in +0 -0
  28. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/__main__.py +0 -0
  29. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/archive.py +0 -0
  30. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/format.py +0 -0
  31. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/method.py +0 -0
  32. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/naming.py +0 -0
  33. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber/progress.py +0 -0
  34. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber.egg-info/dependency_links.txt +0 -0
  35. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber.egg-info/entry_points.txt +0 -0
  36. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/gitlabber.egg-info/top_level.txt +0 -0
  37. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__init__.py +0 -0
  38. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/__init__.cpython-311.pyc +0 -0
  39. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/io_test_util.cpython-311.pyc +0 -0
  40. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_archive.cpython-311-pytest-8.2.2.pyc +0 -0
  41. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_format.cpython-311-pytest-8.2.2.pyc +0 -0
  42. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_method.cpython-311-pytest-8.2.2.pyc +0 -0
  43. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/__pycache__/test_naming.cpython-311-pytest-8.2.2.pyc +0 -0
  44. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/io_test_util.py +0 -0
  45. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test-input.yaml +0 -0
  46. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test-output.json +0 -0
  47. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test-output.tree +0 -0
  48. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test-output.yaml +0 -0
  49. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_archive.py +0 -0
  50. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_e2e.py +0 -0
  51. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_format.py +0 -0
  52. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_integration.py +0 -0
  53. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_method.py +0 -0
  54. {gitlabber-1.2.5.1 → gitlabber-1.2.7}/tests/test_naming.py +0 -0
@@ -1,12 +1,11 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: gitlabber
3
- Version: 1.2.5.1
3
+ Version: 1.2.7
4
4
  Summary: A Gitlab clone/pull utility for backing up or cloning Gitlab groups
5
- Home-page: https://github.com/ezbz/gitlabber
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
@@ -0,0 +1,2 @@
1
+ """ Gitlabber """
2
+ __version__ = '1.2.7'
@@ -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, group_search=args.group_search)
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.debug("Error pulling project %s", action.path, exc_info=True)
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
1
+ Metadata-Version: 2.2
2
2
  Name: gitlabber
3
- Version: 1.2.5.1
3
+ Version: 1.2.7
4
4
  Summary: A Gitlab clone/pull utility for backing up or cloning Gitlab groups
5
- Home-page: https://github.com/ezbz/gitlabber
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
@@ -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
@@ -5,3 +5,9 @@ pyyaml
5
5
  tqdm
6
6
  GitPython
7
7
  python-gitlab
8
+
9
+ [test]
10
+ coverage
11
+ pytest
12
+ pytest-cov
13
+ pytest-integration
@@ -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
@@ -2,7 +2,7 @@
2
2
  universal = 1
3
3
 
4
4
  [metadata]
5
- description-file = README.rst
5
+ description_file = README.rst
6
6
 
7
7
  [coverage:run]
8
8
  parallel = true
@@ -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
+ # )
@@ -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'
@@ -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
- )
File without changes
File without changes
File without changes
File without changes