GithubHelp home page GithubHelp logo

gitlabber's Introduction

image

image

image

image

image

image

Gitlabber

  • A utility to clone and pull GitLab groups, subgroups, projects based on path selection

Purpose

Gitlabber clones or pulls all projects under a subset of groups / subgroups by building a tree from the GitLab API and allowing you to specify which subset of the tree you want to clone using glob patterns and/or regex expressions.

Installation

  • You can install Gitlabber from PyPi:
  • You'll need to create an access token from GitLab with API scopes read_repository and read_api (or api, for GitLab versions <12.0)

Usage

  • Arguments can be provided via the CLI arguments directly or via environment variables::
    Argument Flag Environment Variable
    token -t GITLAB_TOKEN
    url -u GITLAB_URL
    method -m GITLABBER_CLONE_METHOD
    naming -n GITLABBER_FOLDER_NAMING
    include -i GITLABBER_INCLUDE
    exclude -x GITLABBER_EXCLUDE
    root_group -g GITLABBER_ROOT_GROUP
  • To view the tree run the command with your includes/excludes and the -p flag. It will print your tree like so:
  • To see how to use glob patterns and regex to filter tree nodes, see the globre project page.
  • 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.
  • Cloning submodules: use the -r flag to recurse git submodules, uses the --recursive for cloning and utilizes GitPython's smart update method for updating cloned repositories
  • Printed Usage:
usage: gitlabber [-h] [-t token] [-u url] [--verbose] [-p] [-d]
                [--print-format {json,yaml,tree}] [-m {ssh,https}] [-i csv]
                [-x csv] [--version] [-g {id,full_path,full_name}]
                [dest]

Gitlabber - clones or pulls entire groups/projects tree from GitLab

positional arguments:
dest                  destination path for the cloned tree (created if doesn't exist)

optional arguments:
-h, --help            show this help message and exit
-t token, --token token
                        gitlab personal access token https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html
-u url, --url url     base gitlab url (e.g.: 'http://gitlab.mycompany.com')
--verbose             print more verbose output
-p, --print           print the tree without cloning
--print-format {json,yaml,tree}
                        print format (default: 'tree')
-n {name,path}, --naming {name,path}
                        the folder naming strategy for projects (default: "name")
-m {ssh,http}, --method {ssh,http}
                        the git transport method to use for cloning (default: "ssh")
-a {include,exclude,only}, --archived {include,exclude,only}
                        include archived projects and groups in the results (default: "include")
-i csv, --include csv
                        comma delimited list of glob patterns of paths to projects or groups to clone/pull
-x csv, --exclude csv
                        comma delimited list of glob patterns of paths to projects or groups to exclude from clone/pull
-g root_group, --root-group root_group
                        id/full_path/full_name of a group to use as the root instead of the entire gitlab tree
-r, --recursive       clone/pull git submodules recursively
-d, --dont-checkout   clone/fetch git repository without checkout
--version             print the version

examples:

    clone an entire gitlab tree using a base url and a token:
    gitlabber -t <personal access token> -u <gitlab url> .

    # the following examples assume you provided token/url in environment variables so these arguments are omitted
    only print the gitlab tree:
    gitlabber -p .

    clone only projects under subgroup 'MySubGroup' to location '~/GitlabRoot':
    gitlabber -i '/MyGroup/MySubGroup**' ~/GitlabRoot

    clone only projects under group 'MyGroup' excluding any projects under subgroup 'MySubGroup':
    gitlabber -i '/MyGroup**' -x '/MyGroup/MySubGroup**' .

    clone an entire gitlab tree except projects under groups named 'ArchiveGroup':
    gitlabber -x '/ArchiveGroup**' .

    clone projects that start with a case insensitive 'w' using a regular expression:
    gitlabber -i '/{[w].*}' .

Debugging

  • You can use the --verbose flag to print Gitlabber debug messages
  • For more verbose GitLab messages, you can get the GitPython module to print more debug messages by setting the environment variable:

Troubleshooting --------------* `GitlabHttpError: 503`: make sure you provide the base URL to your GitLab installation (e.g., https://gitlab.my.com and not https://gitlab.my.com/some/nested/path)

Known Limitations

  • 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.
  • 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).
  • If you're going to clone a large number of projects, observe rate limits for gitlab.com, and for on-premise installations.

gitlabber's People

Contributors

alvarodelvalle avatar arnvid avatar crocmagnon avatar dependabot[bot] avatar ezbz avatar joubin avatar masecla22 avatar s1artie avatar syphernl avatar waldyrious avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

gitlabber's Issues

Delete

Delete. Posted with the wrong account.

How to run the CLI

I use Ubuntu 18.04.02 LTS

and I installed gitlabber package as mentioned in the Readme using pip.

I ran pip3 install gitlabber

I checked pip3 show gitlabber

the command resulted in the below details

Name: gitlabber
Version: 1.1.0
Summary: A Gitlab clone/pull utility for backing up or cloning Gitlab groups
Home-page: https://github.com/ezbz/gitlabber
Author: Erez Mazor
Author-email: [email protected]
License: MIT
Location: /home/mark/.local/lib/python3.6/site-packages
Requires: python-gitlab, globre, anytree, pyyaml, GitPython, docopt

I checked in the Location: /home/mark/.local/lib/python3.6/site-packages

But I can't find any executable in the gitlabber folder

How to run this package as an executable

"Please specify a destination for the gitlab tree" [dest] check happens only after full GitLab parse

Hi ezbz!

Your volunteer tester here.
Following #49 (tested on latest commit f571544).

$ time gitlabber --verbose -t sometoken -u https://gitlab.some.domain -i '/test-group**'
2021-03-10 19:55:23,536 - gitlabber.cli - DEBUG - verbose=[True], print=[False], log level set to [10] level
2021-03-10 19:55:23,557 - gitlabber.cli - DEBUG - Reading projects tree from gitlab at [https://gitlab.some.domain]
2021-03-10 19:55:23,557 - gitlabber.gitlab_tree - DEBUG - Loading projects tree gitlab server [https://gitlab.some.domain]
2021-03-10 19:55:23,563 - urllib3.connectionpool - DEBUG - Starting new HTTPS connection (1): gitlab.some.domain:443
2021-03-10 19:55:23,842 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups HTTP/1.1" 200 None
2021-03-10 19:55:23,930 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/73/subgroups HTTP/1.1" 200 2
2021-03-10 19:55:24,110 - urllib3.connectionpool - DEBUG - https://gitlab.some.domaine:443 "GET /api/v4/groups/73/projects HTTP/1.1" 200 None
...
...
2021-03-10 19:55:59,158 - gitlabber.gitlab_tree - DEBUG - Loading projects tree from gitlab took [-448722:05:11.47]
2021-03-10 19:55:59,160 - gitlabber.gitlab_tree - DEBUG - Fetched root node with [342] projects
2021-03-10 19:55:59,163 - gitlabber.gitlab_tree - DEBUG - Matched include path [/test-group**] to node [/test-group/test-project-2-archived]
2021-03-10 19:55:59,163 - gitlabber.gitlab_tree - DEBUG - Matched include path [/test-group**] to node [/test-group/test-project-1]
Please specify a destination for the gitlab tree

real    0m35.959s
user    0m1.161s
sys     0m0.074s

Subgroups get cloned many Times

Using GitLab, if you have the following Project-Structure:

myGroup/mySubGroup/mySubSubGroup

and run following Command:

gitlabber -t "**************************" -u "https://git.HOST.com" -m ssh .

Then mySupSupGroup will be Cloned three times:

.
├── myGroup
│   └── mySupGroup
│       └── mySupSupGroup
├── mySupGroup
│   └── mySupSupGroup
└── mySupSupGroup


Editional Information:
Gitlabber Version: 1.1.0
Gitlab Version: GitLab Enterprise Edition 13.4.3-ee
OS: Linux Mint 20
Git Version: 2.25.1

exceptions.GitlabHttpError: 503

gitlabber -u https://gitlab.com/xxx -t **** --verbose -p .

2020-07-19 07:41:54,611 - gitlabber.cli - INFO - Reading projects tree from gitlab at [https://gitlab.com/xxx]
2020-07-19 07:41:54,611 - gitlabber.cli - INFO - Reading projects tree from gitlab at [https://gitlab.com/xxx]
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/gitlab/exceptions.py", line 279, in wrapped_f
    return f(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/gitlab/mixins.py", line 141, in list
    obj = self.gitlab.http_list(path, **data)
  File "/usr/local/lib/python3.7/site-packages/gitlab/__init__.py", line 656, in http_list
    return GitlabList(self, url, query_data, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/gitlab/__init__.py", line 784, in __init__
    self._query(url, query_data, **self._kwargs)
  File "/usr/local/lib/python3.7/site-packages/gitlab/__init__.py", line 789, in _query
    result = self._gl.http_request("get", url, query_data=query_data, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/gitlab/__init__.py", line 575, in http_request
    response_body=result.content,
gitlab.exceptions.GitlabHttpError: 503: <!DOCTYPE html>
<html>
<head>
  <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
  <title>Checking your Browser - GitLab</title>
  <style>body{color:#666;text-align:center;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;margin:auto;font-size:14px;display:flex;flex-direction:column;align-items:center;justify-content:center}hr{max-width:800px;margin:18px auto;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}img{max-width:40vw}.container{margin:auto 20px}.cferror_details{list-style-type:none}.cf-error-details h1{color:#456;font-size:20px;font-weight:400;line-height:28px}</style>
<script type="text/javascript">
  //<![CDATA[
  (function(){

    var a = function() {try{return !!window.addEventListener} catch(e) {return !1} },
    b = function(b, c) {a() ? document.addEventListener("DOMContentLoaded", b, c) : document.attachEvent("onreadystatechange", b)};
    b(function(){
...

Does it work if my workspace is using SSO?

As stated, my workspace is using SSO for login. I am not the admin so I have no way to change this setting. And I also see that when I run the following command. It seems to be redirected to the login page which lead to the whole grabbing process fail. Just wanna confirm that. Thank you very much

Command:

gitlabber --verbose dest='<som path>' -t '<personal token>' -u '<url>' -m 'ssh'

Response

2021-06-19 01:43:15,524 - gitlabber.cli - DEBUG - verbose=[True], print=[False], log level set to [10] level
2021-06-19 01:43:15,564 - gitlabber.cli - DEBUG - Reading projects tree from gitlab at [<url>]
2021-06-19 01:43:15,564 - gitlabber.gitlab_tree - DEBUG - Loading projects tree gitlab server [<url>]
2021-06-19 01:43:15,572 - urllib3.connectionpool - DEBUG - Starting new HTTPS connection (1): <url>:443
2021-06-19 01:43:15,841 - urllib3.connectionpool - DEBUG - <url>:443 "GET .../api/v4/groups HTTP/1.1" 302 102
2021-06-19 01:43:16,022 - urllib3.connectionpool - DEBUG - <url>:443 "GET /users/sign_in HTTP/1.1" 200 None

Empty groups result in 400 and endless retry

I have a sub-group in gitlab which is empty (has no repositories/projects). When I ran gitlabber, it cloned all projects until it encountered this empty group. It then printed a log similar to the following:

2020-07-02 09:36:04,575 - gitlabber.git - ERROR - Cmd('git') failed due to: exit code(128)
  cmdline: git clone -v https://[redacted]/groups/[redacted]/infrastructure/sandbox None/infrastructure/sandbox
  stderr: 'Cloning into 'None/infrastructure/sandbox'...
fatal: unable to access 'https://[redacted]/groups/[redacted]/infrastructure/sandbox/': The requested URL returned error: 400

It then started cloning all the repos again starting from the first.

Not enough scope per the README instruction

Personal access token with read_repository only.

gitlabber request

gitlabber -u https://gitlab.com/ -t [REDACTED] -i '/globalid**' /Users/alvaro/Library/Application\ Support/JetBrains/GoLand2020.1/scratches/repos
2020-07-08 13:59:40,479 - gitlabber.cli - INFO - Reading projects tree from gitlab at [https://gitlab.com/]
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/gitlab/exceptions.py", line 279, in wrapped_f
    return f(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/gitlab/mixins.py", line 141, in list
    obj = self.gitlab.http_list(path, **data)
  File "/usr/local/lib/python3.8/site-packages/gitlab/__init__.py", line 656, in http_list
    return GitlabList(self, url, query_data, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/gitlab/__init__.py", line 780, in __init__
    self._query(url, query_data, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/gitlab/__init__.py", line 785, in _query
    result = self._gl.http_request("get", url, query_data=query_data, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/gitlab/__init__.py", line 572, in http_request
    raise GitlabHttpError(
gitlab.exceptions.GitlabHttpError: 403: insufficient_scope

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/alvaro/Library/Python/3.8/bin/gitlabber", line 8, in <module>
    sys.exit(main())
  File "/Users/alvaro/Library/Python/3.8/lib/python/site-packages/gitlabber/cli.py", line 28, in main
    tree.load_tree()
  File "/Users/alvaro/Library/Python/3.8/lib/python/site-packages/gitlabber/gitlab_tree.py", line 100, in load_tree
    self.load_gitlab_tree()
  File "/Users/alvaro/Library/Python/3.8/lib/python/site-packages/gitlabber/gitlab_tree.py", line 83, in load_gitlab_tree
    groups = self.gitlab.groups.list(as_list=False)
  File "/usr/local/lib/python3.8/site-packages/gitlab/exceptions.py", line 281, in wrapped_f
    raise error(e.error_message, e.response_code, e.response_body) from e
gitlab.exceptions.GitlabListError: 403: insufficient_scope

curl request

curl -s -H 'PRIVATE-TOKEN: [REDACTED]' https://gitlab.com/api/v4/groups/
{"error":"insufficient_scope","error_description":"The request requires higher privileges than provided by the access token.","scope":"api read_api"}%   

I recreated my token with read_api and read_repository and now things are functioning as expected. README.md needs to be updated to reflect the correct scopes required for the command to succeed.

Error installing matplotlib

I am using Python-3.8.2 and recieved the following errors while installing matplotlib

Building wheels for collected packages: subprocess32
Running setup.py bdist_wheel for subprocess32 ... error
Complete output from command /usr/bin/python -u -c "import setuptools, tokenize;file='/tmp/pip-build-1sgYYF/subprocess32/setup.py';f=getattr(tokenize, 'open', open)(file);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, file, 'exec'))" bdist_wheel -d /tmp/tmpFvYzZVpip-wheel- --python-tag cp27:
usage: -c [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
or: -c --help [cmd1 cmd2 ...]
or: -c --help-commands
or: -c cmd --help

error: invalid command 'bdist_wheel'


Failed building wheel for subprocess32
Running setup.py clean for subprocess32
Failed to build subprocess32
Installing collected packages: six, cycler, numpy, backports.functools-lru-cache, subprocess32, setuptools, kiwisolver, pytz, python-dateutil, pyparsing, matplotlib
Running setup.py install for subprocess32 ... error
Complete output from command /usr/bin/python -u -c "import setuptools, tokenize;file='/tmp/pip-build-1sgYYF/subprocess32/setup.py';f=getattr(tokenize, 'open', open)(file);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, file, 'exec'))" install --record /tmp/pip-UA6Da2-record/install-record.txt --single-version-externally-managed --compile --user --prefix=:
running install
running build
running build_py
creating build
creating build/lib.linux-x86_64-2.7
copying subprocess32.py -> build/lib.linux-x86_64-2.7
running build_ext
running build_configure
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking how to run the C preprocessor... gcc -E
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking for unistd.h... (cached) yes
checking fcntl.h usability... yes
checking fcntl.h presence... yes
checking for fcntl.h... yes
checking signal.h usability... yes
checking signal.h presence... yes
checking for signal.h... yes
checking sys/cdefs.h usability... yes
checking sys/cdefs.h presence... yes
checking for sys/cdefs.h... yes
checking for sys/types.h... (cached) yes
checking for sys/stat.h... (cached) yes
checking sys/syscall.h usability... yes
checking sys/syscall.h presence... yes
checking for sys/syscall.h... yes
checking for dirent.h that defines DIR... yes
checking for library containing opendir... none required
checking for pipe2... yes
checking for setsid... yes
checking whether dirfd is declared... yes
configure: creating ./config.status
config.status: creating _posixsubprocess_config.h
building '_posixsubprocess32' extension
creating build/temp.linux-x86_64-2.7
x86_64-linux-gnu-gcc -pthread -fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fdebug-prefix-map=/build/python2.7-UKCoZ3/python2.7-2.7.17=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -I/usr/include/python2.7 -c _posixsubprocess.c -o build/temp.linux-x86_64-2.7/_posixsubprocess.o
_posixsubprocess.c:16:10: fatal error: Python.h: No such file or directory
#include "Python.h"
^~~~~~~~~~
compilation terminated.
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

----------------------------------------

Command "/usr/bin/python -u -c "import setuptools, tokenize;file='/tmp/pip-build-1sgYYF/subprocess32/setup.py';f=getattr(tokenize, 'open', open)(file);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, file, 'exec'))" install --record /tmp/pip-UA6Da2-record/install-record.txt --single-version-externally-managed --compile --user --prefix=" failed with error code 1 in /tmp/pip-build-1sgYYF/subprocess32/

Failure on empty groups (404 not found)

Hi gitlabbers,

i have the following problem when calling gitlabber on internal gitlab site. I try:

gitlabber -t $TOKEN -u https://git....  -m ssh -i '/foo**' -x '**archive**' /Users/devstek/git

This will result me in an exeception for gitlabber and will fail.

* loading tree: 64.3%|███████████████████████████████████████████████████▍                            | 292/454, group=iot-***Traceback (most recent call last):
  File "/Users/devstek/Library/Python/3.7/lib/python/site-packages/gitlab/exceptions.py", line 279, in wrapped_f
    return f(*args, **kwargs)
  File "/Users/devstek/Library/Python/3.7/lib/python/site-packages/gitlab/mixins.py", line 141, in list
    obj = self.gitlab.http_list(path, **data)
  File "/Users/devstek/Library/Python/3.7/lib/python/site-packages/gitlab/__init__.py", line 656, in http_list
    return GitlabList(self, url, query_data, **kwargs)
  File "/Users/devstek/Library/Python/3.7/lib/python/site-packages/gitlab/__init__.py", line 784, in __init__
    self._query(url, query_data, **self._kwargs)
  File "/Users/devstek/Library/Python/3.7/lib/python/site-packages/gitlab/__init__.py", line 789, in _query
    result = self._gl.http_request("get", url, query_data=query_data, **kwargs)
  File "/Users/devstek/Library/Python/3.7/lib/python/site-packages/gitlab/__init__.py", line 575, in http_request
    response_body=result.content,
gitlab.exceptions.GitlabHttpError: 404: 404 Group Not Found

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/devstek/Library/Python/3.7/bin//gitlabber", line 8, in <module>
    sys.exit(main())
  File "/Users/devstek/Library/Python/3.7/lib/python/site-packages/gitlabber/cli.py", line 43, in main
    tree.load_tree()
  File "/Users/devstek/Library/Python/3.7/lib/python/site-packages/gitlabber/gitlab_tree.py", line 144, in load_tree
    self.load_gitlab_tree()
  File "/Users/devstek/Library/Python/3.7/lib/python/site-packages/gitlabber/gitlab_tree.py", line 127, in load_gitlab_tree
    self.get_subgroups(group, node)
  File "/Users/devstek/Library/Python/3.7/lib/python/site-packages/gitlabber/gitlab_tree.py", line 109, in get_subgroups
    subgroups = group.subgroups.list(as_list=False, archived=self.archived)
  File "/Users/devstek/Library/Python/3.7/lib/python/site-packages/gitlab/exceptions.py", line 281, in wrapped_f
    raise error(e.error_message, e.response_code, e.response_body) from e
gitlab.exceptions.GitlabListError: 404: 404 Group Not Found

As a quick workaround and to get it working again, i made a try except block to fix it temporary in gitlab_tree.py

    def get_projects(self, group, parent):
        try:
            projects = group.projects.list(as_list=False, archived=self.archived)
            self.progress.update_progress_length(len(projects))
            self.add_projects(parent, projects)
        except:
            print ("error")

    def get_subgroups(self, group, parent):
        try:
            subgroups = group.subgroups.list(as_list=False, archived=self.archived)
            self.progress.update_progress_length(len(subgroups))
            for subgroup_def in subgroups:
                subgroup = self.gitlab.groups.get(subgroup_def.id)
                subgroup_id = subgroup.name if self.naming == FolderNaming.NAME else subgroup.path
                node = self.make_node(subgroup_id, parent, url=subgroup.web_url)
                self.progress.show_progress(node.name, 'group')
                self.get_subgroups(subgroup, node)
                self.get_projects(subgroup, node)
        except:
            print ("error")

Will you accept pull request for that?

Use system CA certs for SSL connections

My office's GitLab server uses an SSL cert that Python out of the box doesn't seem to like. After much searching, I came across a solution that I was able to splice in and make Gitlabber finally work. I'm mostly writing an issue now as a braindump and at some point I can try to create a PR from my personal laptop.

...

# see https://stackoverflow.com/a/50215614
import requests
from requests.adapters import HTTPAdapter
# from requests.packages.urllib3.util.ssl_ import create_urllib3_context
from ssl import create_default_context

class SSLContextAdapter(HTTPAdapter):
    def init_poolmanager(self, *args, **kwargs):
        context = create_default_context()  # create_urllib3_context()
        kwargs['ssl_context'] = context
        context.load_default_certs() # this loads the OS defaults on Windows
        return super(SSLContextAdapter, self).init_poolmanager(*args, **kwargs)


def get_system_cert_context(url):
    s = requests.Session()
    adapter = SSLContextAdapter()
    s.mount(url, adapter)
    s.get(url)
    return s


class GitlabTree:

    def __init__(self, url, token, method, includes=[], excludes=[], in_file=None, concurrency=1, disable_progress=False):
        self.includes = includes
        self.excludes = excludes
        self.url = url
        self.root = Node("", root_path="", url=url)

        self.gitlab = Gitlab(url, private_token=token,
                             session=get_system_cert_context(url))

...

docs: mention python-certifi-win32

This is somewhat outland-ish, but most likely enabling in a number of scenarios:

Often, gitlab will be installed on-premise, and the certificate for HTTPS will be self-signed, from a private CA. This would be a typical enterprise deployment.

Python on Linux (IIRC - cannot validate right now) will be configured by distributions to (also) point to their (system) CA store.

Python on Windows needs a little bit of help - I just found https://pypi.org/project/python-certifi-win32/ to be extremely helpful in allowing Python to use the CA certificate(s) which are already installed in the Windows (system) certificate store.

If this information about CA certificate stores could be added to the docs, then user experience for gitlabber might be improved:

https://enterprise-gitlab.example.com

will not throw trust exceptions, will just work, also with Windows clients (obviously, the python-certifi-win32 would have to be installed by the user).

Gitlabber not executable from terminal

After successfully installing gitlabber via pip3, now im facing the issue of not being able to execute gitlabber command from the terminal "command not found: gitlabber"

Using "http" method fails on username/password prompt

When setting method to "http", the scripts end up prompting for username/password. This makes it impossible to script gitlabber non-interactively.
The correct way would probably be to:

  1. Make user specify username in addition to token on command-line, and use these.
  2. Integrate with git credentials to get this info.

gitlabber stops at 90,7%

Try to get access to our Internal git via gitlabber but it stops with these error at 90,7%
Maybe you can help:

[15:01:50][User@MDXN00057110:~/tmp2]$ gitlabber -t -u https://git.tech.rz.db.de -p

  • loading tree: 90.7%|██████████████████████████████████████████████████████████████████████████████████████████▋ | 206/227, project=cloudia-iamTraceback (most recent call last):
    File "/usr/lib/python3.6/site-packages/gitlab/exceptions.py", line 279, in wrapped_f
    return f(*args, **kwargs)
    File "/usr/lib/python3.6/site-packages/gitlab/mixins.py", line 50, in get
    server_data = self.gitlab.http_get(path, **kwargs)
    File "/usr/lib/python3.6/site-packages/gitlab/init.py", line 593, in http_get
    "get", path, query_data=query_data, streamed=streamed, **kwargs
    File "/usr/lib/python3.6/site-packages/gitlab/init.py", line 568, in http_request
    response_body=result.content,
    gitlab.exceptions.GitlabHttpError: 500: 500 Internal Server Error

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/usr/bin/gitlabber", line 11, in
sys.exit(main())
File "/usr/lib/python3.6/site-packages/gitlabber/cli.py", line 36, in main
tree.load_tree()
File "/usr/lib/python3.6/site-packages/gitlabber/gitlab_tree.py", line 130, in load_tree
self.load_gitlab_tree()
File "/usr/lib/python3.6/site-packages/gitlabber/gitlab_tree.py", line 113, in load_gitlab_tree
self.get_subgroups(group, node)
File "/usr/lib/python3.6/site-packages/gitlabber/gitlab_tree.py", line 100, in get_subgroups
subgroup = self.gitlab.groups.get(subgroup_def.id)
File "/usr/lib/python3.6/site-packages/gitlab/exceptions.py", line 281, in wrapped_f
raise error(e.error_message, e.response_code, e.response_body) from e
gitlab.exceptions.GitlabGetError: 500: 500 Internal Server Error

I Used:
gitlabber --version 1.1.1
GitLab Community Edition 13.3.9
Linux MDXN00057110 4.4.0-18362-Microsoft #1049-Microsoft Thu Aug 14 12:01:00 PST 2020 x86_64 x86_64 x86_64 GNU/Linux
git version 2.16.4
Python 3.6.12

python 3.8 errors

I am running python 38 and receive the following errors when trying to pull a repo with gitlabber.

My call - gitlabber -t ***** -u https://gitlab..... -p

Traceback (most recent call last):
  File "c:\python38\lib\site-packages\gitlab\__init__.py", line 795, in _query
    self._data = result.json()
  File "c:\python38\lib\site-packages\requests\models.py", line 898, in json
    return complexjson.loads(self.text, **kwargs)
  File "c:\python38\lib\json\__init__.py", line 357, in loads
    return _default_decoder.decode(s)
  File "c:\python38\lib\json\decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "c:\python38\lib\json\decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "c:\python38\lib\runpy.py", line 193, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "c:\python38\lib\runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "C:\Python38\Scripts\gitlabber.exe\__main__.py", line 9, in <module>
  File "c:\python38\lib\site-packages\gitlabber\cli.py", line 27, in main
    tree.load_tree()
  File "c:\python38\lib\site-packages\gitlabber\gitlab_tree.py", line 95, in load_tree
    self.load_gitlab_tree()
  File "c:\python38\lib\site-packages\gitlabber\gitlab_tree.py", line 78, in load_gitlab_tree
    groups= self.gitlab.groups.list(as_list=False)
  File "c:\python38\lib\site-packages\gitlab\exceptions.py", line 275, in wrapped_f
    return f(*args, **kwargs)
  File "c:\python38\lib\site-packages\gitlab\mixins.py", line 141, in list
    obj = self.gitlab.http_list(path, **data)
  File "c:\python38\lib\site-packages\gitlab\__init__.py", line 653, in http_list
    return GitlabList(self, url, query_data, **kwargs)
  File "c:\python38\lib\site-packages\gitlab\__init__.py", line 777, in __init__
    self._query(url, query_data, **kwargs)
  File "c:\python38\lib\site-packages\gitlab\__init__.py", line 797, in _query
    raise GitlabParsingError(
gitlab.exceptions.GitlabParsingError: Failed to parse the server message

GitlabHttpError: 503

Config

  • Ubuntu 20.04.1

  • Python 3.8.5

  • gitlabber 1.1.0

  • Access token generated with read_api and read_repository scopes

Issue

gitlabber -u https://gitlab.com/my-group -t *** --verbose -p .

Outputs:

2020-11-11 17:10:23,658 - gitlabber.cli - INFO - Reading projects tree from gitlab at [https://gitlab.com/my-group]
2020-11-11 17:10:23,658 - gitlabber.cli - INFO - Reading projects tree from gitlab at [https://gitlab.com/my-group]
Traceback (most recent call last):
  File "/home/ubuntu/.venv/lib/python3.8/site-packages/gitlab/exceptions.py", line 279, in wrapped_f
    return f(*args, **kwargs)
  File "/home/ubuntu/.venv/lib/python3.8/site-packages/gitlab/mixins.py", line 141, in list
    obj = self.gitlab.http_list(path, **data)
  File "/home/ubuntu/.venv/lib/python3.8/site-packages/gitlab/__init__.py", line 649, in http_list
    return GitlabList(self, url, query_data, **kwargs)
  File "/home/ubuntu/.venv/lib/python3.8/site-packages/gitlab/__init__.py", line 777, in __init__
    self._query(url, query_data, **self._kwargs)
  File "/home/ubuntu/.venv/lib/python3.8/site-packages/gitlab/__init__.py", line 782, in _query
    result = self._gl.http_request("get", url, query_data=query_data, **kwargs)
  File "/home/ubuntu/.venv/lib/python3.8/site-packages/gitlab/__init__.py", line 565, in http_request
    raise GitlabHttpError(
gitlab.exceptions.GitlabHttpError: 503:

Followed by this HTML:

HTML 1 (click to expand)
<!DOCTYPE html>
<html>
<head>
  <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
  <title>Checking your Browser - GitLab</title>
  <style>body{color:#666;text-align:center;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;margin:auto;font-size:14px;display:flex;flex-direction:column;align-items:center;justify-content:center}hr{max-width:800px;margin:18px auto;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}img{max-width:40vw}.container{margin:auto 20px}.cferror_details{list-style-type:none}.cf-error-details h1{color:#456;font-size:20px;font-weight:400;line-height:28px}</style>
<meta http-equiv="refresh" content="12">
<script type="text/javascript">
  //<![CDATA[
  (function(){
    
    var a = function() {try{return !!window.addEventListener} catch(e) {return !1} },
    b = function(b, c) {a() ? document.addEventListener("DOMContentLoaded", b, c) : document.attachEvent("onreadystatechange", b)};
    b(function(){
      var cookiesEnabled=(navigator.cookieEnabled)? true : false;
      var cookieSupportInfix=cookiesEnabled?'/nocookie':'/cookie';
      var a = document.getElementById('cf-content');a.style.display = 'block';
      var isIE = /(MSIE|Trident\/|Edge\/)/i.test(window.navigator.userAgent);
      var trkjs = isIE ? new Image() : document.createElement('img');
      trkjs.setAttribute("src", "/cdn-cgi/images/trace/jschal/js"+cookieSupportInfix+"/transparent.gif?ray=5f0aa80cbd84f5db");
      trkjs.id = "trk_jschal_js";
      trkjs.setAttribute("alt", "");
      document.body.appendChild(trkjs);
      
      setTimeout(function(){
        var s,t,o,p, b,r,e,a,k,i,n,g,cpo,f, QDLJkCJ={"sDpr":+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))/+((!+[]+(!![])-[]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]))};
        g = String.fromCharCode;
        o = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
        e = function(s) {
          s += "==".slice(2 - (s.length & 3));
          var bm, r = "", r1, r2, i = 0, r3 = '<span class="cf-error-code">1020</span>';
          for (; i < s.length;) {
              bm = o.indexOf(s.charAt(i++)) << 18 | o.indexOf(s.charAt(i++)) << 12
                      | (r1 = o.indexOf(s.charAt(i++))) << 6 | (r2 = o.indexOf(s.charAt(i++)));
              r += r1 === 64 ? g(bm >> 16 & 255)
                      : r2 === 64 ? g(bm >> 16 & 255, bm >> 8 & 255)
                      : g(bm >> 16 & 255, bm >> 8 & 255, bm & 255);
          }
          return r;
        };
        t = document.createElement('div');
        cpo = {};
        t.innerHTML="<a href='/'>x</a>";
        cpo.src = "/cdn-cgi/challenge-platform/h//orchestrate/jsch/v1";
        t = t.firstChild.href;r = (setInterval(function(){}, 100),t.match(/https?:\/\//)[0]);
        t = t.substr(r.length); t = t.substr(0,t.length-1); k = 'YQRySForF';
        a = document.getElementById('jschl+answer'.replace('+', '-'));
        f = document.getElementById('challenge-form'); a.value = '';
        ;QDLJkCJ.sDpr-=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]));QDLJkCJ.sDpr-=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]-(!![]))+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(+!![]));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[]));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])-[])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+[])+(!+[]+(!![])+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]-(!![]))+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])-[])+(+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]-(!![])));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+[])+(!+[]+(!![])-[])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]));QDLJkCJ.sDpr-=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(+!![])+(+!![]));k+=+((!+[]+(!![])-[]+[]));QDLJkCJ.sDpr-=function(p){var p = eval(eval(e("ZG9jdW1l")+(undefined+"")[1]+(true+"")[0]+(+(+!+[]+[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+[!+[]+!+[]]+[+[]])+[])[+!+[]]+g(103)+(true+"")[3]+(true+"")[0]+"Element"+g(66)+(NaN+[Infinity])[10]+"Id("+g(107)+")."+e("aW5uZXJIVE1M"))); return +(p)}();QDLJkCJ.sDpr*=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])-[])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]-(!![])));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(+!![])+(!+[]+(!![])-[])+(!+[]-(!![]))+(+!![]));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]))/+((!+[]+(!![])-[]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]));QDLJkCJ.sDpr-=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])-[])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]))/(+(+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])))+(function(p){return eval((true+"")[0]+".ch"+(false+"")[1]+(true+"")[1]+Function("return escape")()(("")["italics"]())[2]+"o"+(undefined+"")[2]+(true+"")[3]+"A"+(true+"")[0]+"("+p+")")}(+((!+[]+(!![])+!![]+!![]+!![]+[])))));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])-[])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]))/+((!+[]+(!![])-[]+[])+(!+[]+(!![])-[])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]));QDLJkCJ.sDpr*=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))/+((!+[]+(!![])+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]));QDLJkCJ.sDpr*=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]-(!![]))+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![])+(+!![])+(!+[]-(!![]))+(+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]));a.value = (+QDLJkCJ.sDpr).toFixed(10); '; 121'
        f.action += location.hash;
        return  f.submit();
      },4000); /*eoc*/
      
    }, false);
  })();
  //]]>
</script>

</head>

<body>
  <h1>
    <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" alt="GitLab Logo" /><br />
  </h1>
  <div class="container">
    <div class="cf-browser-verification cf-im-under-attack">
  <noscript>
    <h1 data-translate="turn_on_js" style="color:#bd2426;">Please turn JavaScript on and reload the page.</h1>
  </noscript>
  <div id="cf-content" style="display:none">
    
    <div id="cf-bubbles">
      <div class="bubbles"></div>
      <div class="bubbles"></div>
      <div class="bubbles"></div>
    </div>
    <h1><span data-translate="checking_browser">Checking your browser before accessing</span> gitlab.com.</h1>
    
    <div id="no-cookie-warning" data-translate="turn_on_cookies" style="display:none">
      <p data-translate="turn_on_cookies" style="color:#bd2426;">Please enable Cookies and reload the page.</p>
    </div>
    <p data-translate="process_is_automatic">This process is automatic. Your browser will redirect to your requested content shortly.</p>
    <p data-translate="allow_5_secs">Please allow up to 5 seconds&hellip;</p>
  </div>
   
  <form class="challenge-form" id="challenge-form" action="/users/sign_in?__cf_chl_jschl_tk__=01b8789218d7c0478e164efebad7b21e4f03d3d0-1605125424-0-ASBwWzxd-cUD1nbZUkP2xi2K1jeFDE2f0iLr54ZGMAHNFW4Pqcyg_l3-Aslt5dKo6nKYAaj1BFD9Z7oiHIczeDeD492zrSwukxjHy8tzjlprepBzATJMKxOOo2up019PpoSZLTYQUkJaG_qdvDUq2LZ5XEz9pMALtZnOBYFAteGDIPoSwTaid0VemPbOoTbNfUPrvB8fxuHThT3-QeU1USbWcsVEcctUpAqiqfEocagYqVtalJhSTldXOpkoZ_YHVUeYfhXXb-SBNjS0BHylLvFRyG4SL36ApYnZjgcQ9IZfwsSPLb4azwBXBa0aun9WDqzy-Xg1VCr4pi9_jzVQxjJIpgMTswbf1x6u9Z2-MF_e" method="POST" enctype="application/x-www-form-urlencoded">
    <input type="hidden" name="r" value="7f1e929ae346a0afe714939f583829e57d93e103-1605125424-0-ASbqlUitYVDiuY1BKANXSI2GOeV7KJyFpDbNsQc8K0hZDD0voQm73oPDWgPkiqBvv/z1Cm+aPWpBEUm1c1QtYY6FQ7P2CsLBvu2I299dBHX6qTASZCuLSHuh+8U6ECJZlaVw3mZHRXvptSEKMDHChJzTy2KnEHntB4FuLRbzR0t1ouRIrEzRRRN4GI3RCU43yqSdd+MZxQ+qPXaYEk9QWql8yd76eDnwlgx5ojv03hSOsxp0ZWuxLUHkFn45Rinq3zpJiEBIP+zDY/TNNcdxXqOmIvGFdRmS0XZxR/4SbnpTaolCJHgFS+bhtyQDz3DAAItGQ0ssaYkfy/xlVu7bpc08b/DvrsQwqGQj/8wI6U+Jn/LJ+lHcbEETMGXpr4B/L7JGBBJcKHs8AHjljGtmV4BiaAzVSgvYrB2BlGUeHQgGQNxvv2f4mcr5yuRfKdw22GjCAi6kTRQ08m3K6y2gTxEFlNqhA0i+X2X0yYrobU4/Yy/K10290sbp1yjM0WiIkHBHcalYoCvHe/x72JhvfDwGN5mc5B5vD9LHYm3sOFUyLw25aOYqDAeDrMM4yiRrxSCk84S9Sl7blTfIBU8pkEgiqewCG3jlXtZgOQNleZe9F35OxXPCgt4rYP/wcqZ7b61ySho67Ra6bfu4psfBkjViZ/7TNz+AtRiQJdW9H3PKk7Z4R3ZYXJP0/NQx0mElCa+TTuU49pEdc+THrjVmwHyzDKJTdHP3MAR9SUxC8Kglh/xOLKBBEbxFFDn0nqAnI1q3vPnrDIlo5Hwlwr8ewfxbTPYnZDtudoRiJRepjt/MOWlYtCT6SpUSATN7i+40AvES2T9OkxXYDX21Q+wPkRFaYuxrd44KqgCv3LO0/oCz6zymaKdEPBa8j9LQP11ZgUVRsg0yn7//e27iCwbUAIos4xS6r7wsA0hrKnGoMnTAfWskfrdDW0bz0gLtHlzVavW+QI7oh9meFy4sizbQMBbdz4ltPrRaOIvdFATwjr29UVYEIrT68ooqjzmCal5CPg7OeKUTCQw3i9a8eXUh0jRVuuEJnAHgD8wh4hQIk9avXBR853rrRISzx014gF1B/k0r89E98Aqvr9W/I78YSvt0mgFGGPkpYb40suW0BKovIhEKkZDEE/gTIGQo/jHUKpHApy8iDu4HeUN9nFWEzaVk1BOG2QAsJ5kApg0NmfDyl98w5hyLKCZsqXPdzyrqnAyaDz4QfDolNMn+WVPzfmVT6Jy+yvZEKJQHhHLlacZpzu1MVwzWEyCLFJCsMy5YTCct4TZ+dldIevu+jXwMhh2XkOqx4hvKDCrvS2v9DzPF+mb2ALfKz0L+uyglRKku0zfxtdpyvO5gAMJJ5+h8j2ZoDH9LxxeAJ2IH1WKov68c4IursFIUsEyQ+LP9zmNwxdxGdpl6jOagI+qv3WoYI6RKvqIhqcSk7lOJcOkNaV4/F6HUw1GosfZqO9FGsDl4tqqRFBRdh+7WrkCBqd7bKDHGl2I08xCe/fz+QGZdXHXDdoGJqXfeZj2usKHmQ1zuxGBcovRmxPR9xY2ldm9UdqTPq6uVmeXH++vPy011PD7VDdKwfzNc2MZoUZ3o0DxxcGNlxanVzZtK0Ti6JMGKCTcg+WGpok7YHm7Qh7O4EOu3jv2geESx9bC07XhlQjHvqGDcd6vPNXEA8cSigC/pLHcHFDmu8pf+jszr2r2nnYhkA/R2WSujfaJrxCrEZfYUa+2BqAgEXf/QxFjHPwV5tW8QpE+9k9APtaYv9ImD2r+OAzVNzc+VTofFySPVYfVT0sAUW7TuVqQrJEciWN0nYyWRetMZvLKhyF7hX7ZHhDlXTv5LlYGqfBJ32L1b5ss6Sg=="/>
    <input type="hidden" value="8cf27bdaac204cc9bd3c5d03ed0d4cfa" id="jschl-vc" name="jschl_vc"/>
    <!-- <input type="hidden" value="daddc3cb07b36ba15a21034ae2f57c80" id="jschl-vc" name="jschl_vc"/> -->
    <input type="hidden" name="pass" value="1605125428.12-xcm5z5d/ZO"/>
    <input type="hidden" id="jschl-answer" name="jschl_answer"/>
  </form>
  <div style="display:none;visibility:hidden;"><div id="YQRySForF1">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![])))</div><div id="YQRySForF6">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]-(!![]))+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))/+((!+[]+(!![])+!![]+!![]+[])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])-[])+(!+[]-(!![]))+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]))</div><div id="YQRySForF7">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))/+((!+[]+(!![])+!![]+[])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))</div><div id="YQRySForF4">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])-[])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]))</div><div id="YQRySForF5">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]))/+((!+[]+(!![])-[]+[])+(!+[]+(!![])+!![]+!![])+(!+[]-(!![]))+(+!![])+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]))</div><div id="YQRySForF2">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(+!![]))</div><div id="YQRySForF9">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![])+(+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))</div><div id="YQRySForF3">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))/+((!+[]+(!![])+!![]+[])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]))</div><div id="YQRySForF8">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))</div></div>
  <div id="trk_jschal_nojs" style="background-image:url('/cdn-cgi/images/trace/jschal/nojs/transparent.gif?ray=5f0aa80cbd84f5db')"> </div>
</div>

    <hr />
  </div>
</body>
</html>

In addition to the first exception, this is also printed:

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/ubuntu/.venv/bin/gitlabber", line 8, in <module>
    sys.exit(main())
  File "/home/ubuntu/.venv/lib/python3.8/site-packages/gitlabber/cli.py", line 28, in main
    tree.load_tree()
  File "/home/ubuntu/.venv/lib/python3.8/site-packages/gitlabber/gitlab_tree.py", line 100, in load_tree
    self.load_gitlab_tree()
  File "/home/ubuntu/.venv/lib/python3.8/site-packages/gitlabber/gitlab_tree.py", line 83, in load_gitlab_tree
    groups = self.gitlab.groups.list(as_list=False)
  File "/home/ubuntu/.venv/lib/python3.8/site-packages/gitlab/exceptions.py", line 281, in wrapped_f
    raise error(e.error_message, e.response_code, e.response_body) from e
gitlab.exceptions.GitlabListError: 503:

Followed by a second HTML:

HTML 2 (click to expand)
<!DOCTYPE html>
<html>
<head>
  <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
  <title>Checking your Browser - GitLab</title>
  <style>body{color:#666;text-align:center;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;margin:auto;font-size:14px;display:flex;flex-direction:column;align-items:center;justify-content:center}hr{max-width:800px;margin:18px auto;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}img{max-width:40vw}.container{margin:auto 20px}.cferror_details{list-style-type:none}.cf-error-details h1{color:#456;font-size:20px;font-weight:400;line-height:28px}</style>
<meta http-equiv="refresh" content="12">
<script type="text/javascript">
  //<![CDATA[
  (function(){
    
    var a = function() {try{return !!window.addEventListener} catch(e) {return !1} },
    b = function(b, c) {a() ? document.addEventListener("DOMContentLoaded", b, c) : document.attachEvent("onreadystatechange", b)};
    b(function(){
      var cookiesEnabled=(navigator.cookieEnabled)? true : false;
      var cookieSupportInfix=cookiesEnabled?'/nocookie':'/cookie';
      var a = document.getElementById('cf-content');a.style.display = 'block';
      var isIE = /(MSIE|Trident\/|Edge\/)/i.test(window.navigator.userAgent);
      var trkjs = isIE ? new Image() : document.createElement('img');
      trkjs.setAttribute("src", "/cdn-cgi/images/trace/jschal/js"+cookieSupportInfix+"/transparent.gif?ray=5f0aa80cbd84f5db");
      trkjs.id = "trk_jschal_js";
      trkjs.setAttribute("alt", "");
      document.body.appendChild(trkjs);
      
      setTimeout(function(){
        var s,t,o,p, b,r,e,a,k,i,n,g,cpo,f, QDLJkCJ={"sDpr":+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))/+((!+[]+(!![])-[]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]))};
        g = String.fromCharCode;
        o = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
        e = function(s) {
          s += "==".slice(2 - (s.length & 3));
          var bm, r = "", r1, r2, i = 0, r3 = '<span class="cf-error-code">1020</span>';
          for (; i < s.length;) {
              bm = o.indexOf(s.charAt(i++)) << 18 | o.indexOf(s.charAt(i++)) << 12
                      | (r1 = o.indexOf(s.charAt(i++))) << 6 | (r2 = o.indexOf(s.charAt(i++)));
              r += r1 === 64 ? g(bm >> 16 & 255)
                      : r2 === 64 ? g(bm >> 16 & 255, bm >> 8 & 255)
                      : g(bm >> 16 & 255, bm >> 8 & 255, bm & 255);
          }
          return r;
        };
        t = document.createElement('div');
        cpo = {};
        t.innerHTML="<a href='/'>x</a>";
        cpo.src = "/cdn-cgi/challenge-platform/h//orchestrate/jsch/v1";
        t = t.firstChild.href;r = (setInterval(function(){}, 100),t.match(/https?:\/\//)[0]);
        t = t.substr(r.length); t = t.substr(0,t.length-1); k = 'YQRySForF';
        a = document.getElementById('jschl+answer'.replace('+', '-'));
        f = document.getElementById('challenge-form'); a.value = '';
        ;QDLJkCJ.sDpr-=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]));QDLJkCJ.sDpr-=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]-(!![]))+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(+!![]));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[]));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])-[])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+[])+(!+[]+(!![])+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]-(!![]))+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])-[])+(+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]-(!![])));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+[])+(!+[]+(!![])-[])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]));QDLJkCJ.sDpr-=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(+!![])+(+!![]));k+=+((!+[]+(!![])-[]+[]));QDLJkCJ.sDpr-=function(p){var p = eval(eval(e("ZG9jdW1l")+(undefined+"")[1]+(true+"")[0]+(+(+!+[]+[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+[!+[]+!+[]]+[+[]])+[])[+!+[]]+g(103)+(true+"")[3]+(true+"")[0]+"Element"+g(66)+(NaN+[Infinity])[10]+"Id("+g(107)+")."+e("aW5uZXJIVE1M"))); return +(p)}();QDLJkCJ.sDpr*=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])-[])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]-(!![])));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(+!![])+(!+[]+(!![])-[])+(!+[]-(!![]))+(+!![]));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]))/+((!+[]+(!![])-[]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]));QDLJkCJ.sDpr-=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])-[])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]))/(+(+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])))+(function(p){return eval((true+"")[0]+".ch"+(false+"")[1]+(true+"")[1]+Function("return escape")()(("")["italics"]())[2]+"o"+(undefined+"")[2]+(true+"")[3]+"A"+(true+"")[0]+"("+p+")")}(+((!+[]+(!![])+!![]+!![]+!![]+[])))));QDLJkCJ.sDpr+=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])-[])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]))/+((!+[]+(!![])-[]+[])+(!+[]+(!![])-[])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]));QDLJkCJ.sDpr*=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))/+((!+[]+(!![])+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]));QDLJkCJ.sDpr*=+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]-(!![]))+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![])+(+!![])+(!+[]-(!![]))+(+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]));a.value = (+QDLJkCJ.sDpr).toFixed(10); '; 121'
        f.action += location.hash;
        return  f.submit();
      },4000); /*eoc*/
      
    }, false);
  })();
  //]]>
</script>

</head>

<body>
  <h1>
    <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" alt="GitLab Logo" /><br />
  </h1>
  <div class="container">
    <div class="cf-browser-verification cf-im-under-attack">
  <noscript>
    <h1 data-translate="turn_on_js" style="color:#bd2426;">Please turn JavaScript on and reload the page.</h1>
  </noscript>
  <div id="cf-content" style="display:none">
    
    <div id="cf-bubbles">
      <div class="bubbles"></div>
      <div class="bubbles"></div>
      <div class="bubbles"></div>
    </div>
    <h1><span data-translate="checking_browser">Checking your browser before accessing</span> gitlab.com.</h1>
    
    <div id="no-cookie-warning" data-translate="turn_on_cookies" style="display:none">
      <p data-translate="turn_on_cookies" style="color:#bd2426;">Please enable Cookies and reload the page.</p>
    </div>
    <p data-translate="process_is_automatic">This process is automatic. Your browser will redirect to your requested content shortly.</p>
    <p data-translate="allow_5_secs">Please allow up to 5 seconds&hellip;</p>
  </div>
   
  <form class="challenge-form" id="challenge-form" action="/users/sign_in?__cf_chl_jschl_tk__=01b8789218d7c0478e164efebad7b21e4f03d3d0-1605125424-0-ASBwWzxd-cUD1nbZUkP2xi2K1jeFDE2f0iLr54ZGMAHNFW4Pqcyg_l3-Aslt5dKo6nKYAaj1BFD9Z7oiHIczeDeD492zrSwukxjHy8tzjlprepBzATJMKxOOo2up019PpoSZLTYQUkJaG_qdvDUq2LZ5XEz9pMALtZnOBYFAteGDIPoSwTaid0VemPbOoTbNfUPrvB8fxuHThT3-QeU1USbWcsVEcctUpAqiqfEocagYqVtalJhSTldXOpkoZ_YHVUeYfhXXb-SBNjS0BHylLvFRyG4SL36ApYnZjgcQ9IZfwsSPLb4azwBXBa0aun9WDqzy-Xg1VCr4pi9_jzVQxjJIpgMTswbf1x6u9Z2-MF_e" method="POST" enctype="application/x-www-form-urlencoded">
    <input type="hidden" name="r" value="7f1e929ae346a0afe714939f583829e57d93e103-1605125424-0-ASbqlUitYVDiuY1BKANXSI2GOeV7KJyFpDbNsQc8K0hZDD0voQm73oPDWgPkiqBvv/z1Cm+aPWpBEUm1c1QtYY6FQ7P2CsLBvu2I299dBHX6qTASZCuLSHuh+8U6ECJZlaVw3mZHRXvptSEKMDHChJzTy2KnEHntB4FuLRbzR0t1ouRIrEzRRRN4GI3RCU43yqSdd+MZxQ+qPXaYEk9QWql8yd76eDnwlgx5ojv03hSOsxp0ZWuxLUHkFn45Rinq3zpJiEBIP+zDY/TNNcdxXqOmIvGFdRmS0XZxR/4SbnpTaolCJHgFS+bhtyQDz3DAAItGQ0ssaYkfy/xlVu7bpc08b/DvrsQwqGQj/8wI6U+Jn/LJ+lHcbEETMGXpr4B/L7JGBBJcKHs8AHjljGtmV4BiaAzVSgvYrB2BlGUeHQgGQNxvv2f4mcr5yuRfKdw22GjCAi6kTRQ08m3K6y2gTxEFlNqhA0i+X2X0yYrobU4/Yy/K10290sbp1yjM0WiIkHBHcalYoCvHe/x72JhvfDwGN5mc5B5vD9LHYm3sOFUyLw25aOYqDAeDrMM4yiRrxSCk84S9Sl7blTfIBU8pkEgiqewCG3jlXtZgOQNleZe9F35OxXPCgt4rYP/wcqZ7b61ySho67Ra6bfu4psfBkjViZ/7TNz+AtRiQJdW9H3PKk7Z4R3ZYXJP0/NQx0mElCa+TTuU49pEdc+THrjVmwHyzDKJTdHP3MAR9SUxC8Kglh/xOLKBBEbxFFDn0nqAnI1q3vPnrDIlo5Hwlwr8ewfxbTPYnZDtudoRiJRepjt/MOWlYtCT6SpUSATN7i+40AvES2T9OkxXYDX21Q+wPkRFaYuxrd44KqgCv3LO0/oCz6zymaKdEPBa8j9LQP11ZgUVRsg0yn7//e27iCwbUAIos4xS6r7wsA0hrKnGoMnTAfWskfrdDW0bz0gLtHlzVavW+QI7oh9meFy4sizbQMBbdz4ltPrRaOIvdFATwjr29UVYEIrT68ooqjzmCal5CPg7OeKUTCQw3i9a8eXUh0jRVuuEJnAHgD8wh4hQIk9avXBR853rrRISzx014gF1B/k0r89E98Aqvr9W/I78YSvt0mgFGGPkpYb40suW0BKovIhEKkZDEE/gTIGQo/jHUKpHApy8iDu4HeUN9nFWEzaVk1BOG2QAsJ5kApg0NmfDyl98w5hyLKCZsqXPdzyrqnAyaDz4QfDolNMn+WVPzfmVT6Jy+yvZEKJQHhHLlacZpzu1MVwzWEyCLFJCsMy5YTCct4TZ+dldIevu+jXwMhh2XkOqx4hvKDCrvS2v9DzPF+mb2ALfKz0L+uyglRKku0zfxtdpyvO5gAMJJ5+h8j2ZoDH9LxxeAJ2IH1WKov68c4IursFIUsEyQ+LP9zmNwxdxGdpl6jOagI+qv3WoYI6RKvqIhqcSk7lOJcOkNaV4/F6HUw1GosfZqO9FGsDl4tqqRFBRdh+7WrkCBqd7bKDHGl2I08xCe/fz+QGZdXHXDdoGJqXfeZj2usKHmQ1zuxGBcovRmxPR9xY2ldm9UdqTPq6uVmeXH++vPy011PD7VDdKwfzNc2MZoUZ3o0DxxcGNlxanVzZtK0Ti6JMGKCTcg+WGpok7YHm7Qh7O4EOu3jv2geESx9bC07XhlQjHvqGDcd6vPNXEA8cSigC/pLHcHFDmu8pf+jszr2r2nnYhkA/R2WSujfaJrxCrEZfYUa+2BqAgEXf/QxFjHPwV5tW8QpE+9k9APtaYv9ImD2r+OAzVNzc+VTofFySPVYfVT0sAUW7TuVqQrJEciWN0nYyWRetMZvLKhyF7hX7ZHhDlXTv5LlYGqfBJ32L1b5ss6Sg=="/>
    <input type="hidden" value="8cf27bdaac204cc9bd3c5d03ed0d4cfa" id="jschl-vc" name="jschl_vc"/>
    <!-- <input type="hidden" value="daddc3cb07b36ba15a21034ae2f57c80" id="jschl-vc" name="jschl_vc"/> -->
    <input type="hidden" name="pass" value="1605125428.12-xcm5z5d/ZO"/>
    <input type="hidden" id="jschl-answer" name="jschl_answer"/>
  </form>
  <div style="display:none;visibility:hidden;"><div id="YQRySForF1">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![])))</div><div id="YQRySForF6">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]-(!![]))+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))/+((!+[]+(!![])+!![]+!![]+[])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])-[])+(!+[]-(!![]))+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]))</div><div id="YQRySForF7">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))/+((!+[]+(!![])+!![]+[])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]))</div><div id="YQRySForF4">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])-[])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]))</div><div id="YQRySForF5">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]))/+((!+[]+(!![])-[]+[])+(!+[]+(!![])+!![]+!![])+(!+[]-(!![]))+(+!![])+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]))</div><div id="YQRySForF2">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(+!![]))</div><div id="YQRySForF9">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])-[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![])+(+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))</div><div id="YQRySForF3">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))/+((!+[]+(!![])+!![]+[])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]))</div><div id="YQRySForF8">+((!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![])+(+!![])+(!+[]-(!![]))+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))/+((!+[]+(!![])+!![]+!![]+!![]+[])+(!+[]+(!![])+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+(!![])+!![])+(+!![])+(!+[]+(!![])+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))</div></div>
  <div id="trk_jschal_nojs" style="background-image:url('/cdn-cgi/images/trace/jschal/nojs/transparent.gif?ray=5f0aa80cbd84f5db')"> </div>
</div>

    <hr />
  </div>
</body>
</html>

Related

From #23 a fix to this error was presented, which is to include your username at the URL, as in [email protected].
I tried that fix, but it didn't work for me.

Supplied Gitlab token is not being used

I'm running the recursive command in our Gitlab.com repo using the command below but I'm getting the error: Please make sure you have the correct access rights and the repository exists.

I redacted the excerpts of the commands and the logs. For reference:

  • XXX = Gitlab Token
  • AAA/BBB** = Filter for groups and subgroup
  • AAA/BBB/CCC = Group/subgroup
gitlabber -t XXX -u https://gitlab.com -i 'AAA/BBB**' --verbose .

...

'
2021-04-26 18:18:35,712 - gitlabber.git - DEBUG - cloning new project ./AAA/BBB/CCC
2021-04-26 18:18:35,712 - git.cmd - DEBUG - Popen(['git', 'clone', '-v', '[email protected]:AAA/BBB/CCC', './AAA/BBB/CCC'], cwd=/Users/administrator/Documents/gitlab-backups, universal_newlines=True, shell=None, istream=None)
2021-04-26 18:18:37,452 - git.repo.base - DEBUG - Cmd(['git', 'clone', '-v', '[email protected]:AAA/BBB/CCC.git', './AAA/BBB/CCC'])'s unused stdout:
2021-04-26 18:18:37,452 - git.cmd - DEBUG - AutoInterrupt wait stderr: b"Cloning into './AAA/BBB/CCC'...\[email protected]: Permission denied (publickey,keyboard-interactive).\nfatal: Could not read from remote repository.\n\nPlease make sure you have the correct access rights\nand the repository exists.\n"
2021-04-26 18:18:37,452 - gitlabber.git - DEBUG - Error cloning project ./AAA/BBB/CCC
Traceback (most recent call last):
  File "/Users/administrator/.pyenv/versions/3.6.13/lib/python3.6/site-packages/gitlabber/git.py", line 78, in clone_or_pull_project
    git.Repo.clone_from(action.node.url, action.path)
  File "/Users/administrator/.pyenv/versions/3.6.13/lib/python3.6/site-packages/git/repo/base.py", line 1032, in clone_from
    return cls._clone(git, url, to_path, GitCmdObjectDB, progress, multi_options, **kwargs)
  File "/Users/administrator/.pyenv/versions/3.6.13/lib/python3.6/site-packages/git/repo/base.py", line 973, in _clone
    finalize_process(proc, stderr=stderr)
  File "/Users/administrator/.pyenv/versions/3.6.13/lib/python3.6/site-packages/git/util.py", line 329, in finalize_process
    proc.wait(**kwargs)
  File "/Users/administrator/.pyenv/versions/3.6.13/lib/python3.6/site-packages/git/cmd.py", line 408, in wait
    raise GitCommandError(self.args, status, errstr)
git.exc.GitCommandError: Cmd('git') failed due to: exit code(128)
  cmdline: git clone -v [email protected]:/AAA/BBB/CCC.git ./AAA/BBB/CCC
  stderr: 'Cloning into './AAA/BBB/CCC'...
[email protected]: Permission denied (publickey,keyboard-interactive).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
'

...

I'm sure that I have access to the repo and that the token is working. I was able to clone successfully using the command:

git clone https://oauth:[email protected]:/AAA/BBB/CCC.git

Cloning Subgroups doesnt work

Why is it not working?

gitlabber -t TOKEN -u https://git.HOST.de/ -i "/Group/SubGroup**" .

2020-08-04 12:08:14,737 - gitlabber.cli - INFO - Reading projects tree from gitlab at [https://git.HOST.de/]
2020-08-04 12:08:18,931 - gitlabber.cli - ERROR - The tree is empty, check your include/exclude patterns or run with more verbosity for debugging

Feature request: Add support for personal projects

Projects that are in your personal space are currently not taken into account. For individuals using gitlab.com, it would be useful to add those as well. They could either end up in the root directory, or be cloned into a directory with the username, though that might collide with a group with the same name.

Feature request: skip `archived` projects

Dear @ezbz, thank you for the tool.

Currently Gitlabber processes all projects, regardless of archived status.
Can we parameterize it and skip those? I believe it fits the original goal of the project perfectly.

Workaround is to actual move projects to dedicated group, and then ignoring it, e.g. -x '{.*(archived-project$).*}', which is suboptimal.

Please see https://docs.gitlab.com/ee/api/projects.html#list-all-projects:

Attribute Type Required Description
archived boolean No Limit by archived status.

Logs:


$ mkdir TEMP && cd TEMP
$ time gitlabber --verbose -t sometoken -u https://gitlab.some.domain -i '/Test Group**' -p
root [https://gitlab.some.domain]
└── Test Group [/Test Group]
    ├── test-project-2-archived [/Test Group/test-project-2-archived]
    └── test-project-1 [/Test Group/test-project-1]

$ time gitlabber --verbose -t sometoken -u https://gitlab.some.domain -i '/Test Group**'
2021-02-24 11:04:43,263 - gitlabber.cli - DEBUG - verbose=[True], print=[False], log level set to [10] level
2021-02-24 11:04:43,275 - gitlabber.cli - DEBUG - Reading projects tree from gitlab at [https://gitlab.some.domain]
2021-02-24 11:04:43,275 - gitlabber.gitlab_tree - DEBUG - Loading projects tree gitlab server [https://gitlab.some.domain]
2021-02-24 11:04:43,278 - urllib3.connectionpool - DEBUG - Starting new HTTPS connection (1): gitlab.some.domain:443
2021-02-24 11:04:43,536 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups HTTP/1.1" 200 None
...
2021-02-24 11:04:58,264 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/67/projects HTTP/1.1" 200 None
2021-02-24 11:04:58,409 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/66/projects HTTP/1.1" 200 None
2021-02-24 11:04:58,413 - urllib3.connectionpool - DEBUG - Resetting dropped connection: gitlab.some.domain
2021-02-24 11:04:58,651 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/188/subgroups HTTP/1.1" 200 2
2021-02-24 11:04:58,834 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/188/projects HTTP/1.1" 200 None
2021-02-24 11:04:58,914 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/8/subgroups HTTP/1.1" 200 2
...
2021-02-24 11:05:20,124 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/161/projects HTTP/1.1" 200 None
2021-02-24 11:05:20,204 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/13/subgroups HTTP/1.1" 200 2
2021-02-24 11:05:20,351 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/13/projects HTTP/1.1" 200 None
2021-02-24 11:05:20,353 - gitlabber.gitlab_tree - DEBUG - Loading projects tree from gitlab took [-448378:55:53.28]
2021-02-24 11:05:20,355 - gitlabber.gitlab_tree - DEBUG - Fetched root node with [338] projects
2021-02-24 11:05:20,358 - gitlabber.gitlab_tree - DEBUG - Matched include path [/Test Group**] to node [/Test Group/test-project-2-archived]
2021-02-24 11:05:20,358 - gitlabber.gitlab_tree - DEBUG - Matched include path [/Test Group**] to node [/Test Group/test-project-1]
2021-02-24 11:05:20,379 - gitlabber.gitlab_tree - DEBUG - Going to clone/pull [1] groups and [2] projects
2021-02-24 11:05:20,384 - gitlabber.git - DEBUG - cloning new project None/Test Group/test-project-2-archived
2021-02-24 11:05:20,385 - git.cmd - DEBUG - Popen(['git', 'clone', '-v', '[email protected]:test-group/test-project-2-archived.git', 'None/Test Group/test-project-2-archived'], cwd=/home/someuser/gitlab/TEMP, universal_newlines=True, shell=None, istream=None)
2021-02-24 11:05:21,858 - git.repo.base - DEBUG - Cmd(['git', 'clone', '-v', '[email protected]:test-group/test-project-2-archived.git', 'None/Test Group/test-project-2-archived'])'s unused stdout: 
2021-02-24 11:05:21,867 - gitlabber.git - DEBUG - cloning new project None/Test Group/test-project-1
2021-02-24 11:05:21,867 - git.cmd - DEBUG - Popen(['git', 'clone', '-v', '[email protected]:test-group/test-project-1.git', 'None/Test Group/test-project-1'], cwd=/home/someuser/gitlab/TEMP, universal_newlines=True, shell=None, istream=None)
2021-02-24 11:05:22,853 - git.repo.base - DEBUG - Cmd(['git', 'clone', '-v', '[email protected]:test-group/test-project-1.git', 'None/Test Group/test-project-1'])'s unused stdout: 
2021-02-24 11:05:22,863 - gitlabber.git - DEBUG - Syncing projects took [None]

$ ls None/Test\ Group/
test-project-1  test-project-2-archived

use project path instead of project name

Hello,

it would be nice if it was possible to generate folder name based on project path, because the name doesn't always reflect the correct project path.

For exemple i have theses projects

root
├── Project 1 [/project1]
|   ├── Project 1 Front [/project1/front]
|   └── Project 1 Api [/project1/api]
└── Project 2 [/project2]
    ├── Project 2 Front [/project2/front]
    └── Project 2 Api [/project2/api]

it creates the following folders

root
├── Project 1
|   ├── Project 1 Front
|   └── Project 1 Api
└── Project 2
    ├── Project 2 Front
    └── Project 2 Api

but I would like

root
├── project1
|   ├── front
|   ├── api
└── project2
    ├── front
    └── api

Clone into "path" not "name"

This seems like a really useful tool, however I don't understand why it would clone into directories that use the project/group name rather than the "path" from Gitlab?

Maybe an option could be made to clone into directories based on the Gitlab path?

Does not grab all branches/tags

I ran the tool on a gitlab instance and when i went to move it, it didn't have any of the other branches or tags for many of the repositories. Does this do a clone operation for the default branch? Was wondering if there might be arguments I missed for grabbing everything.

Tree is confused by sub-groups

Greetings,

I have a project 'P' that is in group 'G' and sub-group 'S'. When I run gitlabber -p, I see

root [https://gitlab.com]
|---G [/G]
|      |---S [/G/S/]
|      |      |---P [/G/S/P]
|
|---S [/S]
|      |---P [/S/P]

Similarly, I have copies of P's repo in repo/G/S/P and repo/S/P. In both cases the remote points back to the correct location /G/S/P

In a complex set of projects and sub-projects - this creates a bit of a mess...

Christopher

It can't make it work

Hi,
I was trying to test this tool, but the script always fails. Just to make an example, I would clone all the repo of a public project (this).

I've launched the following command

 gitlabber  -u https://gitlab.com/ -i /csns_accelerator* .

it says, after many seconds:

2020-04-30 11:35:44,261 - gitlabber.cli - ERROR - The tree is empty, check your include/exclude patterns or run with the -v for debugging

What's wrong?

--include could parse less groups/projects

We have a somewhat large Gitlab instance with ~600 projects in various groups and subgroups. Currently, when running the following command, gitlabber still parses the whole tree my user has access to to generate its tree and it takes a long time. I feel like we could optimize the retrieval to parse only the specified branches in simple cases.

gitlabber -p -i "/mygroup/**" -a exclude

The progress bar clearly shows that all other groups/subgroups are parsed, even if they have no chance of matching this glob pattern.

I'd expect the previous command to only scan projects and subgroups inside mygroup.

Similarly, if multiple include flags are passed that can directly match a group, go through these groups only.

A glob that ends with a / and one or two stars and doesn't contain any other star or question mark should allow for this optimization.

IIRC Gitlab offers a "search" API that can return groups matching some criteria.

  • gitlabber version 1.1.8

gitlabber inside python script

Hi,

I'm new at Python and is searching a way to import gitlabber inside my script.

# I thought something like that 
import gitlabber

GITLAB_URL = 'http://localhost'
GITLABBER_INCLUDE = 'foo'
GITLAB_TOKEN = 'fake_token'

gitlabber('GITLAB_TOKEN', 'GITLAB_URL', G'ITLABBER_INCLUDE')

but i that's not the right way. Could you please help me that would be awesome :)

thank you 👍

Ignore custom Gitlab certificates

We are using an internal on-premises Gitlab instance with custom certificate.
Is there a way (option?) to bypass the certificate verification?

`
Traceback (most recent call last):
File "/home/username/anaconda3/lib/python3.8/site-packages/urllib3/connectionpool.py", line 670, in urlopen
httplib_response = self._make_request(
File "/home/username/anaconda3/lib/python3.8/site-packages/urllib3/connectionpool.py", line 381, in _make_request
self._validate_conn(conn)
File "/home/username/anaconda3/lib/python3.8/site-packages/urllib3/connectionpool.py", line 978, in validate_conn
conn.connect()
File "/home/username/anaconda3/lib/python3.8/site-packages/urllib3/connection.py", line 362, in connect
self.sock = ssl_wrap_socket(
File "/home/username/anaconda3/lib/python3.8/site-packages/urllib3/util/ssl
.py", line 386, in ssl_wrap_socket
return context.wrap_socket(sock, server_hostname=server_hostname)
File "/home/username/anaconda3/lib/python3.8/ssl.py", line 500, in wrap_socket
return self.sslsocket_class._create(
File "/home/username/anaconda3/lib/python3.8/ssl.py", line 1040, in _create
self.do_handshake()
File "/home/username/anaconda3/lib/python3.8/ssl.py", line 1309, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1123)

`

How to specify ssh key to be used?

I have multiple Gitlab accounts - cannot use the same ssh key for all so I have multiple keys in my .ssh folder...
I dont need to all accounts to be cloned at once, can do it one by one but how to specify which key should be used?
Thanks, great project!

Error installing matplotlib

I am using Python-3.8.2 and recieved the following errors while installing matplotlib using
pip install matplotlib

Building wheels for collected packages: subprocess32
Running setup.py bdist_wheel for subprocess32 ... error
Complete output from command /usr/bin/python -u -c "import setuptools, tokenize;file='/tmp/pip-build-1sgYYF/subprocess32/setup.py';f=getattr(tokenize, 'open', open)(file);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, file, 'exec'))" bdist_wheel -d /tmp/tmpFvYzZVpip-wheel- --python-tag cp27:
usage: -c [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
or: -c --help [cmd1 cmd2 ...]
or: -c --help-commands
or: -c cmd --help

error: invalid command 'bdist_wheel'


Failed building wheel for subprocess32
Running setup.py clean for subprocess32
Failed to build subprocess32
Installing collected packages: six, cycler, numpy, backports.functools-lru-cache, subprocess32, setuptools, kiwisolver, pytz, python-dateutil, pyparsing, matplotlib
Running setup.py install for subprocess32 ... error
Complete output from command /usr/bin/python -u -c "import setuptools, tokenize;file='/tmp/pip-build-1sgYYF/subprocess32/setup.py';f=getattr(tokenize, 'open', open)(file);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, file, 'exec'))" install --record /tmp/pip-UA6Da2-record/install-record.txt --single-version-externally-managed --compile --user --prefix=:
running install
running build
running build_py
creating build
creating build/lib.linux-x86_64-2.7
copying subprocess32.py -> build/lib.linux-x86_64-2.7
running build_ext
running build_configure
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking how to run the C preprocessor... gcc -E
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking for unistd.h... (cached) yes
checking fcntl.h usability... yes
checking fcntl.h presence... yes
checking for fcntl.h... yes
checking signal.h usability... yes
checking signal.h presence... yes
checking for signal.h... yes
checking sys/cdefs.h usability... yes
checking sys/cdefs.h presence... yes
checking for sys/cdefs.h... yes
checking for sys/types.h... (cached) yes
checking for sys/stat.h... (cached) yes
checking sys/syscall.h usability... yes
checking sys/syscall.h presence... yes
checking for sys/syscall.h... yes
checking for dirent.h that defines DIR... yes
checking for library containing opendir... none required
checking for pipe2... yes
checking for setsid... yes
checking whether dirfd is declared... yes
configure: creating ./config.status
config.status: creating _posixsubprocess_config.h
building '_posixsubprocess32' extension
creating build/temp.linux-x86_64-2.7
x86_64-linux-gnu-gcc -pthread -fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fdebug-prefix-map=/build/python2.7-UKCoZ3/python2.7-2.7.17=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -I/usr/include/python2.7 -c _posixsubprocess.c -o build/temp.linux-x86_64-2.7/_posixsubprocess.o
_posixsubprocess.c:16:10: fatal error: Python.h: No such file or directory
#include "Python.h"
^~~~~~~~~~
compilation terminated.
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

----------------------------------------

Command "/usr/bin/python -u -c "import setuptools, tokenize;file='/tmp/pip-build-1sgYYF/subprocess32/setup.py';f=getattr(tokenize, 'open', open)(file);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, file, 'exec'))" install --record /tmp/pip-UA6Da2-record/install-record.txt --single-version-externally-managed --compile --user --prefix=" failed with error code 1 in /tmp/pip-build-1sgYYF/subprocess32/

Shouldn't retrieve moved projects

$ gitlabber -p -i "/mygroup/**" -a exclude
root [https://git.example.com]
└── mygroup [/mygroup]
    ├── valid1 [/mygroup/valid1]
    ├── non-existant [/mygroup/non-existant]
    ├── valid2 [/mygroup/valid2]
    └── valid3 [/mygroup/valid3]

I'm pretty sure that this project was here before but has since been moved elsewhere.
When cloning, the project is cloned with a remote matching its new location.

Expected behavior:
The non-existant project shouldn't be retrieved.

Gitlabber should use the token(s) from .git-credentials

In case no token is supplied via the -t flag and the environmental variable GITLAB_TOKEN is empty, gitlabber should try to read the .git-credentials file and look for a matching token.

A lot of people already use a personal access token to authenticate themselves, which can also be potentially used by gitlabber.
These access tokens are saved in the .git-credentials file inside users home directory.
The file is just a list of all access tokens in the format

https://username:[email protected]

Thus, gitlabber can try to read the file and see if a matching access token exists.

If [dest] is not given, it defaults to "None"

Hello!

If one forgets to add destination folder, below "None" folder shinanigen happens %)
We can make DEST mandatory parameter, or we can simply set specific default value.

I would argue, that former approach is better.

Logs

$ mkdir TEMP && cd TEMP
$ time gitlabber --verbose -t sometoken -u https://gitlab.some.domain -i '/Test Group**' -p
root [https://gitlab.some.domain]
└── Test Group [/Test Group]
    ├── test-project-2-archived [/Test Group/test-project-2-archived]
    └── test-project-1 [/Test Group/test-project-1]

$ time gitlabber --verbose -t sometoken -u https://gitlab.some.domain -i '/Test Group**'
2021-02-24 11:04:43,263 - gitlabber.cli - DEBUG - verbose=[True], print=[False], log level set to [10] level
2021-02-24 11:04:43,275 - gitlabber.cli - DEBUG - Reading projects tree from gitlab at [https://gitlab.some.domain]
2021-02-24 11:04:43,275 - gitlabber.gitlab_tree - DEBUG - Loading projects tree gitlab server [https://gitlab.some.domain]
2021-02-24 11:04:43,278 - urllib3.connectionpool - DEBUG - Starting new HTTPS connection (1): gitlab.some.domain:443
2021-02-24 11:04:43,536 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups HTTP/1.1" 200 None
...
2021-02-24 11:04:58,264 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/67/projects HTTP/1.1" 200 None
2021-02-24 11:04:58,409 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/66/projects HTTP/1.1" 200 None
2021-02-24 11:04:58,413 - urllib3.connectionpool - DEBUG - Resetting dropped connection: gitlab.some.domain
2021-02-24 11:04:58,651 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/188/subgroups HTTP/1.1" 200 2
2021-02-24 11:04:58,834 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/188/projects HTTP/1.1" 200 None
2021-02-24 11:04:58,914 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/8/subgroups HTTP/1.1" 200 2
...
2021-02-24 11:05:20,124 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/161/projects HTTP/1.1" 200 None
2021-02-24 11:05:20,204 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/13/subgroups HTTP/1.1" 200 2
2021-02-24 11:05:20,351 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/13/projects HTTP/1.1" 200 None
2021-02-24 11:05:20,353 - gitlabber.gitlab_tree - DEBUG - Loading projects tree from gitlab took [-448378:55:53.28]
2021-02-24 11:05:20,355 - gitlabber.gitlab_tree - DEBUG - Fetched root node with [338] projects
2021-02-24 11:05:20,358 - gitlabber.gitlab_tree - DEBUG - Matched include path [/Test Group**] to node [/Test Group/test-project-2-archived]
2021-02-24 11:05:20,358 - gitlabber.gitlab_tree - DEBUG - Matched include path [/Test Group**] to node [/Test Group/test-project-1]
2021-02-24 11:05:20,379 - gitlabber.gitlab_tree - DEBUG - Going to clone/pull [1] groups and [2] projects
2021-02-24 11:05:20,384 - gitlabber.git - DEBUG - cloning new project None/Test Group/test-project-2-archived
2021-02-24 11:05:20,385 - git.cmd - DEBUG - Popen(['git', 'clone', '-v', '[email protected]:test-group/test-project-2-archived.git', 'None/Test Group/test-project-2-archived'], cwd=/home/someuser/gitlab/TEMP, universal_newlines=True, shell=None, istream=None)
2021-02-24 11:05:21,858 - git.repo.base - DEBUG - Cmd(['git', 'clone', '-v', '[email protected]:test-group/test-project-2-archived.git', 'None/Test Group/test-project-2-archived'])'s unused stdout: 
2021-02-24 11:05:21,867 - gitlabber.git - DEBUG - cloning new project None/Test Group/test-project-1
2021-02-24 11:05:21,867 - git.cmd - DEBUG - Popen(['git', 'clone', '-v', '[email protected]:test-group/test-project-1.git', 'None/Test Group/test-project-1'], cwd=/home/someuser/gitlab/TEMP, universal_newlines=True, shell=None, istream=None)
2021-02-24 11:05:22,853 - git.repo.base - DEBUG - Cmd(['git', 'clone', '-v', '[email protected]:test-group/test-project-1.git', 'None/Test Group/test-project-1'])'s unused stdout: 
2021-02-24 11:05:22,863 - gitlabber.git - DEBUG - Syncing projects took [None]

$ ls None/Test\ Group/
test-project-1  test-project-2-archived

-r/--recursive fails, builds invalid git clone command

Thank you for gitlabber. Passing either "-r" or "--recursive"
fails. It passes '-', '-', 'r', 'e', 'c', 'u', 'r', 's', 'i', 'v', 'e' to git clone, see below.

> gitlabber --version
1.1.7
gitlabber -t XXX --url https://XXX -r -a exclude -i '/XXX/**,/YYY/**' --verbose .

Excerpt from the verbose log:

2021-03-19 09:45:36,114 - gitlabber.git - DEBUG - cloning new project ./XXX/YYY
2021-03-19 09:45:36,114 - git.cmd - DEBUG - Popen(['git', 'clone', '-v', '-', '-', 'r', 'e', 'c', 'u', 'r', 's', 'i', 'v', 'e', 'git@XXX:XXX/YYY.git', './XXX/YYY'], cwd=/ZZZ, universal_newlines=True, shell=None, istream=None)
2021-03-19 09:45:36,116 - git.repo.base - DEBUG - Cmd(['git', 'clone', '-v', '-', '-', 'r', 'e', 'c', 'u', 'r', 's', 'i', 'v', 'e', 'git@XXX:XXX/YYY.git', './XXX/YYY'])'s unused stdout: 
2021-03-19 09:45:36,116 - git.cmd - DEBUG - AutoInterrupt wait stderr: b"fatal: Too many arguments.\n\nusage: git clone [<options>] [--] <repo> [<dir>]\n\n    -v, --verbose         be more verbose\n    -q, --quiet           be more quiet\n    --progress            force progress reporting\n    -n, --no-checkout     don't create a checkout\n    --bare                create a bare repository\n    --mirror              create a mirror repository (implies bare)\n    -l, --local           to clone from a local repository\n    --no-hardlinks        don't use local hardlinks, always copy\n    -s, --shared          setup as shared repository\n    --recurse-submodules[=<pathspec>]\n                          initialize submodules in the clone\n    --recursive ...       alias of --recurse-submodules\n    -j, --jobs <n>        number of submodules cloned in parallel\n    --template <template-directory>\n                          directory from which templates will be used\n    --reference <repo>    reference repository\n    --reference-if-able <repo>\n                          reference repository\n    --dissociate          use --reference only while cloning\n    -o, --origin <name>   use <name> instead of 'origin' to track upstream\n    -b, --branch <branch>\n                          checkout <branch> instead of the remote's HEAD\n    -u, --upload-pack <path>\n                          path to git-upload-pack on the remote\n    --depth <depth>       create a shallow clone of that depth\n    --shallow-since <time>\n                          create a shallow clone since a specific time\n    --shallow-exclude <revision>\n                          deepen history of shallow clone, excluding rev\n    --single-branch       clone only one branch, HEAD or --branch\n    --no-tags             don't clone any tags, and make later fetches not to follow them\n    --shallow-submodules  any cloned submodules will be shallow\n    --separate-git-dir <gitdir>\n                          separate git dir from working tree\n    -c, --config <key=value>\n                          set config inside the new repository\n    --server-option <server-specific>\n                          option to transmit\n    -4, --ipv4            use IPv4 addresses only\n    -6, --ipv6            use IPv6 addresses only\n    --filter <args>       object filtering\n    --remote-submodules   any cloned submodules will use their remote-tracking branch\n    --sparse              initialize sparse-checkout file to include only files at root\n\n"
2021-03-19 09:45:36,116 - gitlabber.git - DEBUG - Error cloning project ./XXX/YYY
Traceback (most recent call last):
  File "/XXX/.direnv/python-3.8.6/lib/python3.8/site-packages/gitlabber/git.py", line 76, in clone_or_pull_project
    git.Repo.clone_from(action.node.url, action.path, multi_options='--recursive')
  File "/XXX/.direnv/python-3.8.6/lib/python3.8/site-packages/git/repo/base.py", line 1032, in clone_from
    return cls._clone(git, url, to_path, GitCmdObjectDB, progress, multi_options, **kwargs)
  File "/XXX/.direnv/python-3.8.6/lib/python3.8/site-packages/git/repo/base.py", line 973, in _clone
    finalize_process(proc, stderr=stderr)
  File "/XXX/.direnv/python-3.8.6/lib/python3.8/site-packages/git/util.py", line 329, in finalize_process
    proc.wait(**kwargs)
  File "/XXX/.direnv/python-3.8.6/lib/python3.8/site-packages/git/cmd.py", line 408, in wait
    raise GitCommandError(self.args, status, errstr)
git.exc.GitCommandError: Cmd('git') failed due to: exit code(129)
  cmdline: git clone -v - - r e c u r s i v e git@XXX:XXX/YYY.git ./XXX/YYY

Regarding use for backups

Not really a bug, but some questions:
I want to use gitlabber for backing up my repositories from Gitlab.

How does gitlabber behave then? Should I simply rerun it? Will it clone new repositories and update (fetch) existing?

Is there a "mirror mode" (git clone --mirror ; git remote update)?

Thanks a lot

Feature request: --path parameter to impact Group/Subgroup names too

Hello @ezbz,

both issues #25 and #38, and PR #39 were talking about Projects AND Groups.

However, it seems final PR #43 implemented only Project naming strategy.
I believe that was not intentional and we can build upon PR #43, and extend it to Groups.

Thanks!

Logs

$ mkdir TEMP && cd TEMP
$ time gitlabber --verbose -t sometoken -u https://gitlab.some.domain -i '/Test Group**' -p
root [https://gitlab.some.domain]
└── Test Group [/Test Group]
    ├── test-project-2-archived [/Test Group/test-project-2-archived]
    └── test-project-1 [/Test Group/test-project-1]

$ time gitlabber --verbose -t sometoken -u https://gitlab.some.domain -i '/Test Group**'
2021-02-24 11:04:43,263 - gitlabber.cli - DEBUG - verbose=[True], print=[False], log level set to [10] level
2021-02-24 11:04:43,275 - gitlabber.cli - DEBUG - Reading projects tree from gitlab at [https://gitlab.some.domain]
2021-02-24 11:04:43,275 - gitlabber.gitlab_tree - DEBUG - Loading projects tree gitlab server [https://gitlab.some.domain]
2021-02-24 11:04:43,278 - urllib3.connectionpool - DEBUG - Starting new HTTPS connection (1): gitlab.some.domain:443
2021-02-24 11:04:43,536 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups HTTP/1.1" 200 None
...
2021-02-24 11:04:58,264 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/67/projects HTTP/1.1" 200 None
2021-02-24 11:04:58,409 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/66/projects HTTP/1.1" 200 None
2021-02-24 11:04:58,413 - urllib3.connectionpool - DEBUG - Resetting dropped connection: gitlab.some.domain
2021-02-24 11:04:58,651 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/188/subgroups HTTP/1.1" 200 2
2021-02-24 11:04:58,834 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/188/projects HTTP/1.1" 200 None
2021-02-24 11:04:58,914 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/8/subgroups HTTP/1.1" 200 2
...
2021-02-24 11:05:20,124 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/161/projects HTTP/1.1" 200 None
2021-02-24 11:05:20,204 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/13/subgroups HTTP/1.1" 200 2
2021-02-24 11:05:20,351 - urllib3.connectionpool - DEBUG - https://gitlab.some.domain:443 "GET /api/v4/groups/13/projects HTTP/1.1" 200 None
2021-02-24 11:05:20,353 - gitlabber.gitlab_tree - DEBUG - Loading projects tree from gitlab took [-448378:55:53.28]
2021-02-24 11:05:20,355 - gitlabber.gitlab_tree - DEBUG - Fetched root node with [338] projects
2021-02-24 11:05:20,358 - gitlabber.gitlab_tree - DEBUG - Matched include path [/Test Group**] to node [/Test Group/test-project-2-archived]
2021-02-24 11:05:20,358 - gitlabber.gitlab_tree - DEBUG - Matched include path [/Test Group**] to node [/Test Group/test-project-1]
2021-02-24 11:05:20,379 - gitlabber.gitlab_tree - DEBUG - Going to clone/pull [1] groups and [2] projects
2021-02-24 11:05:20,384 - gitlabber.git - DEBUG - cloning new project None/Test Group/test-project-2-archived
2021-02-24 11:05:20,385 - git.cmd - DEBUG - Popen(['git', 'clone', '-v', '[email protected]:test-group/test-project-2-archived.git', 'None/Test Group/test-project-2-archived'], cwd=/home/someuser/gitlab/TEMP, universal_newlines=True, shell=None, istream=None)
2021-02-24 11:05:21,858 - git.repo.base - DEBUG - Cmd(['git', 'clone', '-v', '[email protected]:test-group/test-project-2-archived.git', 'None/Test Group/test-project-2-archived'])'s unused stdout: 
2021-02-24 11:05:21,867 - gitlabber.git - DEBUG - cloning new project None/Test Group/test-project-1
2021-02-24 11:05:21,867 - git.cmd - DEBUG - Popen(['git', 'clone', '-v', '[email protected]:test-group/test-project-1.git', 'None/Test Group/test-project-1'], cwd=/home/someuser/gitlab/TEMP, universal_newlines=True, shell=None, istream=None)
2021-02-24 11:05:22,853 - git.repo.base - DEBUG - Cmd(['git', 'clone', '-v', '[email protected]:test-group/test-project-1.git', 'None/Test Group/test-project-1'])'s unused stdout: 
2021-02-24 11:05:22,863 - gitlabber.git - DEBUG - Syncing projects took [None]

$ ls None/Test\ Group/
test-project-1  test-project-2-archived

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.