gitlabber 2.1.0__tar.gz → 2.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gitlabber-2.1.0/gitlabber.egg-info → gitlabber-2.1.2}/PKG-INFO +5 -3
- {gitlabber-2.1.0 → gitlabber-2.1.2}/README.rst +2 -1
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/__init__.py +1 -1
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/cli.py +13 -1
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/config.py +1 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/git.py +21 -7
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/gitlab_tree.py +5 -1
- {gitlabber-2.1.0 → gitlabber-2.1.2/gitlabber.egg-info}/PKG-INFO +5 -3
- gitlabber-2.1.2/gitlabber.egg-info/SOURCES.txt +57 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber.egg-info/requires.txt +2 -1
- {gitlabber-2.1.0 → gitlabber-2.1.2}/pyproject.toml +7 -3
- gitlabber-2.1.2/tests/test_git.py +499 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_helpers.py +9 -1
- gitlabber-2.1.0/gitlabber.egg-info/SOURCES.txt +0 -129
- gitlabber-2.1.0/tests/__pycache__/__init__.cpython-311.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/__init__.cpython-312.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/__init__.cpython-313.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/conftest.cpython-311-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/conftest.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/gitlab_test_utils.cpython-311.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/gitlab_test_utils.cpython-312.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/gitlab_test_utils.cpython-313.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/io_test_util.cpython-311.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/io_test_util.cpython-312.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/io_test_util.cpython-313.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_archive.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_archive.cpython-312-pytest-8.3.3.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_archive.cpython-312-pytest-8.3.4.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_archive.cpython-312-pytest-8.3.5.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_archive.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_auth.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_cli.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_cli.cpython-311-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_cli.cpython-312-pytest-8.3.3.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_cli.cpython-312-pytest-8.3.4.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_cli.cpython-312-pytest-8.3.5.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_cli.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_cli_token_storage.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_config.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_e2e.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_e2e.cpython-312-pytest-8.3.3.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_e2e.cpython-312-pytest-8.3.4.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_e2e.cpython-312-pytest-8.3.5.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_e2e.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_e2e.cpython-313.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_exceptions.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_format.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_format.cpython-312-pytest-8.3.3.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_format.cpython-312-pytest-8.3.4.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_format.cpython-312-pytest-8.3.5.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_format.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_git.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_git.cpython-312-pytest-8.3.3.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_git.cpython-312-pytest-8.3.4.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_git.cpython-312-pytest-8.3.5.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_git.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_gitlab_tree.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_gitlab_tree.cpython-312-pytest-8.3.3.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_gitlab_tree.cpython-312-pytest-8.3.4.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_gitlab_tree.cpython-312-pytest-8.3.5.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_gitlab_tree.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_helpers.cpython-311-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_helpers.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_integration.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_integration.cpython-311-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_integration.cpython-312-pytest-8.3.3.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_integration.cpython-312-pytest-8.3.4.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_integration.cpython-312-pytest-8.3.5.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_integration.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_main.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_method.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_method.cpython-312-pytest-8.3.3.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_method.cpython-312-pytest-8.3.4.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_method.cpython-312-pytest-8.3.5.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_method.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_naming.cpython-311-pytest-8.2.2.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_naming.cpython-312-pytest-8.3.3.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_naming.cpython-312-pytest-8.3.4.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_naming.cpython-312-pytest-8.3.5.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_naming.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_performance.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_performance.cpython-313.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_progress.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_rate_limiter.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_token_storage.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/__pycache__/test_url_builder.cpython-313-pytest-9.0.1.pyc +0 -0
- gitlabber-2.1.0/tests/test_git.py +0 -219
- {gitlabber-2.1.0 → gitlabber-2.1.2}/LICENSE.txt +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/MANIFEST.in +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/__main__.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/archive.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/auth.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/exceptions.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/format.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/method.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/naming.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/progress.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/rate_limiter.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/token_storage.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/tree_builder.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber/url_builder.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber.egg-info/dependency_links.txt +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber.egg-info/entry_points.txt +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/gitlabber.egg-info/top_level.txt +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/setup.cfg +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/setup.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/__init__.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/conftest.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/gitlab_test_utils.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/io_test_util.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test-input.yaml +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test-output.json +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test-output.tree +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test-output.yaml +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_archive.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_auth.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_cli.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_cli_token_storage.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_config.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_e2e.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_exceptions.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_format.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_gitlab_tree.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_integration.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_main.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_method.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_naming.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_performance.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_progress.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_rate_limiter.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_token_storage.py +0 -0
- {gitlabber-2.1.0 → gitlabber-2.1.2}/tests/test_url_builder.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gitlabber
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.2
|
|
4
4
|
Summary: A Gitlab clone/pull utility for backing up or cloning Gitlab groups
|
|
5
5
|
Author-email: Erez Mazor <erezmazor@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -26,8 +26,9 @@ Requires-Dist: pyyaml
|
|
|
26
26
|
Requires-Dist: pydantic>=2.7
|
|
27
27
|
Requires-Dist: pydantic-settings>=2.7
|
|
28
28
|
Requires-Dist: typer>=0.12
|
|
29
|
+
Requires-Dist: urllib3>=2.7.0
|
|
29
30
|
Requires-Dist: rich
|
|
30
|
-
Requires-Dist: GitPython
|
|
31
|
+
Requires-Dist: GitPython>=3.1.59
|
|
31
32
|
Requires-Dist: python-gitlab
|
|
32
33
|
Provides-Extra: test
|
|
33
34
|
Requires-Dist: coverage; extra == "test"
|
|
@@ -229,7 +230,8 @@ Usage
|
|
|
229
230
|
number of concurrent git operations (default: 1)
|
|
230
231
|
--api-concurrency N number of concurrent API calls for tree building (default: 5)
|
|
231
232
|
-r, --recursive clone/pull git submodules recursively
|
|
232
|
-
-F, --use-fetch
|
|
233
|
+
-F, --use-fetch use git fetch instead of pull for updates (normal repositories with working tree)
|
|
234
|
+
--mirror create bare mirror repositories (for backups, automatically uses fetch)
|
|
233
235
|
-s, --include-shared include shared projects in the results
|
|
234
236
|
-g term, --group-search term
|
|
235
237
|
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)
|
|
@@ -189,7 +189,8 @@ Usage
|
|
|
189
189
|
number of concurrent git operations (default: 1)
|
|
190
190
|
--api-concurrency N number of concurrent API calls for tree building (default: 5)
|
|
191
191
|
-r, --recursive clone/pull git submodules recursively
|
|
192
|
-
-F, --use-fetch
|
|
192
|
+
-F, --use-fetch use git fetch instead of pull for updates (normal repositories with working tree)
|
|
193
|
+
--mirror create bare mirror repositories (for backups, automatically uses fetch)
|
|
193
194
|
-s, --include-shared include shared projects in the results
|
|
194
195
|
-g term, --group-search term
|
|
195
196
|
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)
|
|
@@ -118,6 +118,8 @@ def config_logging(verbose: bool, print_mode: bool) -> None:
|
|
|
118
118
|
os.environ["GIT_PYTHON_TRACE"] = "full"
|
|
119
119
|
else:
|
|
120
120
|
logging.getLogger().setLevel(logging.INFO)
|
|
121
|
+
# Suppress urllib3 connection pool warnings unless verbose mode is enabled
|
|
122
|
+
logging.getLogger("urllib3.connectionpool").setLevel(logging.ERROR)
|
|
121
123
|
|
|
122
124
|
|
|
123
125
|
def _version_callback(value: bool) -> None:
|
|
@@ -211,6 +213,7 @@ def run_gitlabber(
|
|
|
211
213
|
exclude: Optional[str],
|
|
212
214
|
recursive: bool,
|
|
213
215
|
use_fetch: bool,
|
|
216
|
+
mirror: bool,
|
|
214
217
|
include_shared: bool,
|
|
215
218
|
group_search: Optional[str],
|
|
216
219
|
user_projects: bool,
|
|
@@ -244,6 +247,7 @@ def run_gitlabber(
|
|
|
244
247
|
exclude: Comma-separated glob patterns to exclude
|
|
245
248
|
recursive: Clone submodules recursively
|
|
246
249
|
use_fetch: Use git fetch instead of pull
|
|
250
|
+
mirror: Create bare mirror repositories (implies use_fetch)
|
|
247
251
|
include_shared: Include shared projects
|
|
248
252
|
group_search: Search term for filtering groups at API level
|
|
249
253
|
user_projects: Fetch only user personal projects
|
|
@@ -295,6 +299,7 @@ def run_gitlabber(
|
|
|
295
299
|
"recursive": recursive,
|
|
296
300
|
"include_shared": include_shared,
|
|
297
301
|
"use_fetch": use_fetch,
|
|
302
|
+
"mirror": mirror,
|
|
298
303
|
"hide_token": hide_token,
|
|
299
304
|
"user_projects": user_projects,
|
|
300
305
|
"group_search": group_search,
|
|
@@ -318,6 +323,7 @@ def run_gitlabber(
|
|
|
318
323
|
disable_progress=verbose,
|
|
319
324
|
include_shared=include_shared,
|
|
320
325
|
use_fetch=use_fetch,
|
|
326
|
+
mirror=mirror,
|
|
321
327
|
hide_token=hide_token,
|
|
322
328
|
user_projects=user_projects,
|
|
323
329
|
group_search=group_search,
|
|
@@ -458,7 +464,7 @@ def cli(
|
|
|
458
464
|
False,
|
|
459
465
|
"-F",
|
|
460
466
|
"--use-fetch",
|
|
461
|
-
help="Use git fetch instead of pull (
|
|
467
|
+
help="Use git fetch instead of pull for updates (normal repositories with working tree)",
|
|
462
468
|
),
|
|
463
469
|
exclude_shared: bool = typer.Option(
|
|
464
470
|
False,
|
|
@@ -495,6 +501,11 @@ def cli(
|
|
|
495
501
|
"--store-token",
|
|
496
502
|
help="Store token securely in OS keyring (requires keyring package)",
|
|
497
503
|
),
|
|
504
|
+
mirror: bool = typer.Option(
|
|
505
|
+
False,
|
|
506
|
+
"--mirror",
|
|
507
|
+
help="Create bare mirror repositories (for backups, automatically uses fetch)",
|
|
508
|
+
),
|
|
498
509
|
) -> None:
|
|
499
510
|
"""Main CLI command for gitlabber.
|
|
500
511
|
|
|
@@ -560,6 +571,7 @@ def cli(
|
|
|
560
571
|
exclude=exclude,
|
|
561
572
|
recursive=recursive,
|
|
562
573
|
use_fetch=use_fetch,
|
|
574
|
+
mirror=mirror,
|
|
563
575
|
include_shared=include_shared_value,
|
|
564
576
|
group_search=group_search,
|
|
565
577
|
user_projects=user_projects,
|
|
@@ -26,6 +26,7 @@ class GitAction:
|
|
|
26
26
|
use_fetch: bool = False
|
|
27
27
|
hide_token: bool = False
|
|
28
28
|
git_options: Optional[str] = None
|
|
29
|
+
mirror: bool = False # New parameter
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
class GitRepository:
|
|
@@ -68,7 +69,7 @@ class GitRepository:
|
|
|
68
69
|
multi_options: list[str] = []
|
|
69
70
|
if action.recursive:
|
|
70
71
|
multi_options.append('--recursive')
|
|
71
|
-
if action.
|
|
72
|
+
if action.mirror: # New parameter
|
|
72
73
|
multi_options.append('--mirror')
|
|
73
74
|
if action.git_options:
|
|
74
75
|
multi_options += action.git_options.split(',')
|
|
@@ -132,13 +133,15 @@ class GitRepository:
|
|
|
132
133
|
GitlabberGitError: If pull operation fails
|
|
133
134
|
"""
|
|
134
135
|
log.debug("updating existing project %s", action.path)
|
|
135
|
-
|
|
136
|
+
# Mirror implies use_fetch, so check both
|
|
137
|
+
should_fetch = action.use_fetch or action.mirror
|
|
138
|
+
operation = 'fetching' if should_fetch else 'pulling'
|
|
136
139
|
progress_bar.show_progress_detailed(action.node.name, 'project', operation)
|
|
137
140
|
|
|
138
141
|
try:
|
|
139
142
|
if repo is None:
|
|
140
143
|
repo = git.Repo(action.path)
|
|
141
|
-
if not
|
|
144
|
+
if not should_fetch:
|
|
142
145
|
repo.remotes.origin.pull()
|
|
143
146
|
else:
|
|
144
147
|
repo.remotes.origin.fetch()
|
|
@@ -226,6 +229,7 @@ class GitActionCollector:
|
|
|
226
229
|
dest: str,
|
|
227
230
|
recursive: bool = False,
|
|
228
231
|
use_fetch: bool = False,
|
|
232
|
+
mirror: bool = False,
|
|
229
233
|
hide_token: bool = False,
|
|
230
234
|
git_options: Optional[str] = None
|
|
231
235
|
):
|
|
@@ -235,12 +239,14 @@ class GitActionCollector:
|
|
|
235
239
|
dest: Destination directory for repositories
|
|
236
240
|
recursive: Whether to clone recursively
|
|
237
241
|
use_fetch: Whether to use git fetch instead of pull
|
|
242
|
+
mirror: Whether to create bare mirror repositories
|
|
238
243
|
hide_token: Whether to hide token in URLs
|
|
239
244
|
git_options: Additional git options as comma-separated string
|
|
240
245
|
"""
|
|
241
246
|
self.dest = Path(dest)
|
|
242
247
|
self.recursive = recursive
|
|
243
248
|
self.use_fetch = use_fetch
|
|
249
|
+
self.mirror = mirror
|
|
244
250
|
self.hide_token = hide_token
|
|
245
251
|
self.git_options = git_options
|
|
246
252
|
|
|
@@ -272,9 +278,11 @@ class GitActionCollector:
|
|
|
272
278
|
path_str = str(path)
|
|
273
279
|
|
|
274
280
|
if child.is_leaf:
|
|
281
|
+
# Mirror implies use_fetch (mirrors should always use fetch)
|
|
282
|
+
effective_use_fetch = self.use_fetch or self.mirror
|
|
275
283
|
actions.append(GitAction(
|
|
276
284
|
child, path_str, self.recursive,
|
|
277
|
-
self.
|
|
285
|
+
effective_use_fetch, self.hide_token, self.git_options, self.mirror
|
|
278
286
|
))
|
|
279
287
|
|
|
280
288
|
if not child.is_leaf:
|
|
@@ -307,6 +315,7 @@ class GitSyncManager:
|
|
|
307
315
|
dest: str,
|
|
308
316
|
recursive: bool = False,
|
|
309
317
|
use_fetch: bool = False,
|
|
318
|
+
mirror: bool = False,
|
|
310
319
|
hide_token: bool = False,
|
|
311
320
|
git_options: Optional[str] = None
|
|
312
321
|
) -> None:
|
|
@@ -317,6 +326,7 @@ class GitSyncManager:
|
|
|
317
326
|
dest: Destination directory
|
|
318
327
|
recursive: Whether to clone recursively
|
|
319
328
|
use_fetch: Whether to use git fetch instead of pull
|
|
329
|
+
mirror: Whether to create bare mirror repositories
|
|
320
330
|
hide_token: Whether to hide token in URLs
|
|
321
331
|
git_options: Additional git options as comma-separated string
|
|
322
332
|
"""
|
|
@@ -324,7 +334,7 @@ class GitSyncManager:
|
|
|
324
334
|
self.progress_bar.init_progress(len(root.leaves))
|
|
325
335
|
|
|
326
336
|
collector = GitActionCollector(
|
|
327
|
-
dest, recursive, use_fetch, hide_token, git_options
|
|
337
|
+
dest, recursive, use_fetch, mirror, hide_token, git_options
|
|
328
338
|
)
|
|
329
339
|
actions = collector.collect(root)
|
|
330
340
|
|
|
@@ -343,6 +353,7 @@ def sync_tree(
|
|
|
343
353
|
disable_progress: bool = False,
|
|
344
354
|
recursive: bool = False,
|
|
345
355
|
use_fetch: bool = False,
|
|
356
|
+
mirror: bool = False,
|
|
346
357
|
hide_token: bool = False,
|
|
347
358
|
git_options: Optional[str] = None
|
|
348
359
|
) -> None:
|
|
@@ -356,11 +367,12 @@ def sync_tree(
|
|
|
356
367
|
disable_progress: Whether to disable progress reporting
|
|
357
368
|
recursive: Whether to clone recursively
|
|
358
369
|
use_fetch: Whether to use git fetch instead of pull
|
|
370
|
+
mirror: Whether to create bare mirror repositories
|
|
359
371
|
hide_token: Whether to hide token in URLs
|
|
360
372
|
git_options: Additional git options as comma-separated string
|
|
361
373
|
"""
|
|
362
374
|
manager = GitSyncManager(concurrency, disable_progress)
|
|
363
|
-
manager.sync(root, dest, recursive, use_fetch, hide_token, git_options)
|
|
375
|
+
manager.sync(root, dest, recursive, use_fetch, mirror, hide_token, git_options)
|
|
364
376
|
|
|
365
377
|
|
|
366
378
|
def get_git_actions(
|
|
@@ -368,6 +380,7 @@ def get_git_actions(
|
|
|
368
380
|
dest: str,
|
|
369
381
|
recursive: bool,
|
|
370
382
|
use_fetch: bool,
|
|
383
|
+
mirror: bool,
|
|
371
384
|
hide_token: bool,
|
|
372
385
|
git_options: Optional[str] = None
|
|
373
386
|
) -> list[GitAction]:
|
|
@@ -378,13 +391,14 @@ def get_git_actions(
|
|
|
378
391
|
dest: Destination directory
|
|
379
392
|
recursive: Whether to clone recursively
|
|
380
393
|
use_fetch: Whether to use git fetch instead of pull
|
|
394
|
+
mirror: Whether to create bare mirror repositories
|
|
381
395
|
hide_token: Whether to hide token in URLs
|
|
382
396
|
git_options: Additional git options as comma-separated string
|
|
383
397
|
|
|
384
398
|
Returns:
|
|
385
399
|
List of GitAction objects to execute
|
|
386
400
|
"""
|
|
387
|
-
collector = GitActionCollector(dest, recursive, use_fetch, hide_token, git_options)
|
|
401
|
+
collector = GitActionCollector(dest, recursive, use_fetch, mirror, hide_token, git_options)
|
|
388
402
|
return collector.collect(root)
|
|
389
403
|
|
|
390
404
|
|
|
@@ -45,6 +45,7 @@ class GitlabTree:
|
|
|
45
45
|
disable_progress: bool = False,
|
|
46
46
|
include_shared: bool = True,
|
|
47
47
|
use_fetch: bool = False,
|
|
48
|
+
mirror: bool = False,
|
|
48
49
|
hide_token: bool = False,
|
|
49
50
|
user_projects: bool = False,
|
|
50
51
|
group_search: Optional[str] = None,
|
|
@@ -69,6 +70,7 @@ class GitlabTree:
|
|
|
69
70
|
disable_progress: Whether to disable progress bar (used if config not provided)
|
|
70
71
|
include_shared: Whether to include shared projects (used if config not provided)
|
|
71
72
|
use_fetch: Whether to use git fetch instead of pull (used if config not provided)
|
|
73
|
+
mirror: Whether to create bare mirror repositories (used if config not provided)
|
|
72
74
|
hide_token: Whether to hide token in URLs (used if config not provided)
|
|
73
75
|
user_projects: Whether to fetch only user projects (used if config not provided)
|
|
74
76
|
group_search: Search term for filtering groups (used if config not provided)
|
|
@@ -98,6 +100,7 @@ class GitlabTree:
|
|
|
98
100
|
disable_progress = config.disable_progress
|
|
99
101
|
include_shared = config.include_shared
|
|
100
102
|
use_fetch = config.use_fetch
|
|
103
|
+
mirror = config.mirror
|
|
101
104
|
hide_token = config.hide_token
|
|
102
105
|
user_projects = config.user_projects
|
|
103
106
|
group_search = config.group_search
|
|
@@ -175,6 +178,7 @@ class GitlabTree:
|
|
|
175
178
|
self.token = token
|
|
176
179
|
self.include_shared = include_shared
|
|
177
180
|
self.use_fetch = use_fetch
|
|
181
|
+
self.mirror = mirror
|
|
178
182
|
self.hide_token = hide_token
|
|
179
183
|
self.user_projects = user_projects
|
|
180
184
|
self.group_search = group_search
|
|
@@ -308,7 +312,7 @@ class GitlabTree:
|
|
|
308
312
|
len(self.root.descendants) - len(self.root.leaves), len(self.root.leaves))
|
|
309
313
|
sync_tree(self.root, dest, concurrency=self.concurrency,
|
|
310
314
|
disable_progress=self.disable_progress, recursive=self.recursive,
|
|
311
|
-
use_fetch=self.use_fetch, hide_token=self.hide_token,
|
|
315
|
+
use_fetch=self.use_fetch, mirror=self.mirror, hide_token=self.hide_token,
|
|
312
316
|
git_options=self.git_options)
|
|
313
317
|
except GitlabberGitError:
|
|
314
318
|
# Re-raise git errors as-is
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gitlabber
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.2
|
|
4
4
|
Summary: A Gitlab clone/pull utility for backing up or cloning Gitlab groups
|
|
5
5
|
Author-email: Erez Mazor <erezmazor@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -26,8 +26,9 @@ Requires-Dist: pyyaml
|
|
|
26
26
|
Requires-Dist: pydantic>=2.7
|
|
27
27
|
Requires-Dist: pydantic-settings>=2.7
|
|
28
28
|
Requires-Dist: typer>=0.12
|
|
29
|
+
Requires-Dist: urllib3>=2.7.0
|
|
29
30
|
Requires-Dist: rich
|
|
30
|
-
Requires-Dist: GitPython
|
|
31
|
+
Requires-Dist: GitPython>=3.1.59
|
|
31
32
|
Requires-Dist: python-gitlab
|
|
32
33
|
Provides-Extra: test
|
|
33
34
|
Requires-Dist: coverage; extra == "test"
|
|
@@ -229,7 +230,8 @@ Usage
|
|
|
229
230
|
number of concurrent git operations (default: 1)
|
|
230
231
|
--api-concurrency N number of concurrent API calls for tree building (default: 5)
|
|
231
232
|
-r, --recursive clone/pull git submodules recursively
|
|
232
|
-
-F, --use-fetch
|
|
233
|
+
-F, --use-fetch use git fetch instead of pull for updates (normal repositories with working tree)
|
|
234
|
+
--mirror create bare mirror repositories (for backups, automatically uses fetch)
|
|
233
235
|
-s, --include-shared include shared projects in the results
|
|
234
236
|
-g term, --group-search term
|
|
235
237
|
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)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
LICENSE.txt
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.rst
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.cfg
|
|
6
|
+
setup.py
|
|
7
|
+
gitlabber/__init__.py
|
|
8
|
+
gitlabber/__main__.py
|
|
9
|
+
gitlabber/archive.py
|
|
10
|
+
gitlabber/auth.py
|
|
11
|
+
gitlabber/cli.py
|
|
12
|
+
gitlabber/config.py
|
|
13
|
+
gitlabber/exceptions.py
|
|
14
|
+
gitlabber/format.py
|
|
15
|
+
gitlabber/git.py
|
|
16
|
+
gitlabber/gitlab_tree.py
|
|
17
|
+
gitlabber/method.py
|
|
18
|
+
gitlabber/naming.py
|
|
19
|
+
gitlabber/progress.py
|
|
20
|
+
gitlabber/rate_limiter.py
|
|
21
|
+
gitlabber/token_storage.py
|
|
22
|
+
gitlabber/tree_builder.py
|
|
23
|
+
gitlabber/url_builder.py
|
|
24
|
+
gitlabber.egg-info/PKG-INFO
|
|
25
|
+
gitlabber.egg-info/SOURCES.txt
|
|
26
|
+
gitlabber.egg-info/dependency_links.txt
|
|
27
|
+
gitlabber.egg-info/entry_points.txt
|
|
28
|
+
gitlabber.egg-info/requires.txt
|
|
29
|
+
gitlabber.egg-info/top_level.txt
|
|
30
|
+
tests/__init__.py
|
|
31
|
+
tests/conftest.py
|
|
32
|
+
tests/gitlab_test_utils.py
|
|
33
|
+
tests/io_test_util.py
|
|
34
|
+
tests/test-input.yaml
|
|
35
|
+
tests/test-output.json
|
|
36
|
+
tests/test-output.tree
|
|
37
|
+
tests/test-output.yaml
|
|
38
|
+
tests/test_archive.py
|
|
39
|
+
tests/test_auth.py
|
|
40
|
+
tests/test_cli.py
|
|
41
|
+
tests/test_cli_token_storage.py
|
|
42
|
+
tests/test_config.py
|
|
43
|
+
tests/test_e2e.py
|
|
44
|
+
tests/test_exceptions.py
|
|
45
|
+
tests/test_format.py
|
|
46
|
+
tests/test_git.py
|
|
47
|
+
tests/test_gitlab_tree.py
|
|
48
|
+
tests/test_helpers.py
|
|
49
|
+
tests/test_integration.py
|
|
50
|
+
tests/test_main.py
|
|
51
|
+
tests/test_method.py
|
|
52
|
+
tests/test_naming.py
|
|
53
|
+
tests/test_performance.py
|
|
54
|
+
tests/test_progress.py
|
|
55
|
+
tests/test_rate_limiter.py
|
|
56
|
+
tests/test_token_storage.py
|
|
57
|
+
tests/test_url_builder.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "gitlabber"
|
|
7
|
-
version = "2.1.
|
|
7
|
+
version = "2.1.2"
|
|
8
8
|
description = "A Gitlab clone/pull utility for backing up or cloning Gitlab groups"
|
|
9
9
|
readme = "README.rst"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -32,8 +32,9 @@ dependencies = [
|
|
|
32
32
|
"pydantic>=2.7",
|
|
33
33
|
"pydantic-settings>=2.7",
|
|
34
34
|
"typer>=0.12",
|
|
35
|
+
"urllib3>=2.7.0",
|
|
35
36
|
"rich",
|
|
36
|
-
"GitPython",
|
|
37
|
+
"GitPython>=3.1.59",
|
|
37
38
|
"python-gitlab",
|
|
38
39
|
]
|
|
39
40
|
|
|
@@ -99,4 +100,7 @@ exclude_lines = [
|
|
|
99
100
|
"if TYPE_CHECKING:",
|
|
100
101
|
"class .*\\bProtocol\\):",
|
|
101
102
|
"@(abc\\.)?abstractmethod",
|
|
102
|
-
]
|
|
103
|
+
]
|
|
104
|
+
[tool.ruff.lint]
|
|
105
|
+
# Pin to ruff's classic default rule set; newer ruff releases expand the defaults
|
|
106
|
+
select = ["E4", "E7", "E9", "F"]
|