mirror of
https://github.com/josegonzalez/python-github-backup.git
synced 2025-12-05 16:18:02 +01:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07e32b186c | ||
|
|
dcc90b747a | ||
|
|
f414fac108 | ||
|
|
38692bc836 | ||
|
|
81362e5596 | ||
|
|
753a26d0d6 | ||
|
|
b629a865f4 | ||
|
|
75ec773a6f | ||
|
|
f8a16ee0f8 | ||
|
|
63441ebfbc | ||
|
|
7ad324225e | ||
|
|
885e94a102 |
@@ -41,8 +41,8 @@ CLI Usage is as follows::
|
|||||||
[-P] [-F] [--prefer-ssh] [-v]
|
[-P] [-F] [--prefer-ssh] [-v]
|
||||||
[--keychain-name OSX_KEYCHAIN_ITEM_NAME]
|
[--keychain-name OSX_KEYCHAIN_ITEM_NAME]
|
||||||
[--keychain-account OSX_KEYCHAIN_ITEM_ACCOUNT]
|
[--keychain-account OSX_KEYCHAIN_ITEM_ACCOUNT]
|
||||||
[--releases] [--assets] [--throttle-limit THROTTLE_LIMIT]
|
[--releases] [--assets] [--exclude [REPOSITORY [REPOSITORY ...]]
|
||||||
[--throttle-pause THROTTLE_PAUSE]
|
[--throttle-limit THROTTLE_LIMIT] [--throttle-pause THROTTLE_PAUSE]
|
||||||
USER
|
USER
|
||||||
|
|
||||||
Backup a github account
|
Backup a github account
|
||||||
@@ -112,6 +112,8 @@ CLI Usage is as follows::
|
|||||||
binaries
|
binaries
|
||||||
--assets include assets alongside release information; only
|
--assets include assets alongside release information; only
|
||||||
applies if including releases
|
applies if including releases
|
||||||
|
--exclude [REPOSITORY [REPOSITORY ...]]
|
||||||
|
names of repositories to exclude from backup.
|
||||||
--throttle-limit THROTTLE_LIMIT
|
--throttle-limit THROTTLE_LIMIT
|
||||||
start throttling of GitHub API requests after this
|
start throttling of GitHub API requests after this
|
||||||
amount of API requests remain
|
amount of API requests remain
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = '0.40.2'
|
__version__ = '0.42.0'
|
||||||
|
|||||||
@@ -239,6 +239,10 @@ def parse_args(args=None):
|
|||||||
action='store_true',
|
action='store_true',
|
||||||
dest='bare_clone',
|
dest='bare_clone',
|
||||||
help='clone bare repositories')
|
help='clone bare repositories')
|
||||||
|
parser.add_argument('--no-prune',
|
||||||
|
action='store_true',
|
||||||
|
dest='no_prune',
|
||||||
|
help='disable prune option for git fetch')
|
||||||
parser.add_argument('--lfs',
|
parser.add_argument('--lfs',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
dest='lfs_clone',
|
dest='lfs_clone',
|
||||||
@@ -324,6 +328,10 @@ def parse_args(args=None):
|
|||||||
type=float,
|
type=float,
|
||||||
default=30.0,
|
default=30.0,
|
||||||
help='wait this amount of seconds when API request throttling is active (default: 30.0, requires --throttle-limit to be set)')
|
help='wait this amount of seconds when API request throttling is active (default: 30.0, requires --throttle-limit to be set)')
|
||||||
|
parser.add_argument('--exclude',
|
||||||
|
dest='exclude',
|
||||||
|
help='names of repositories to exclude',
|
||||||
|
nargs="*")
|
||||||
return parser.parse_args(args)
|
return parser.parse_args(args)
|
||||||
|
|
||||||
|
|
||||||
@@ -533,12 +541,12 @@ def _get_response(request, auth, template):
|
|||||||
r = exc
|
r = exc
|
||||||
except URLError as e:
|
except URLError as e:
|
||||||
log_warning(e.reason)
|
log_warning(e.reason)
|
||||||
should_continue = _request_url_error(template, retry_timeout)
|
should_continue, retry_timeout = _request_url_error(template, retry_timeout)
|
||||||
if not should_continue:
|
if not should_continue:
|
||||||
raise
|
raise
|
||||||
except socket.error as e:
|
except socket.error as e:
|
||||||
log_warning(e.strerror)
|
log_warning(e.strerror)
|
||||||
should_continue = _request_url_error(template, retry_timeout)
|
should_continue, retry_timeout = _request_url_error(template, retry_timeout)
|
||||||
if not should_continue:
|
if not should_continue:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@@ -598,16 +606,15 @@ def _request_http_error(exc, auth, errors):
|
|||||||
|
|
||||||
|
|
||||||
def _request_url_error(template, retry_timeout):
|
def _request_url_error(template, retry_timeout):
|
||||||
# Incase of a connection timing out, we can retry a few time
|
# In case of a connection timing out, we can retry a few time
|
||||||
# But we won't crash and not back-up the rest now
|
# But we won't crash and not back-up the rest now
|
||||||
log_info('{} timed out'.format(template))
|
log_info('{} timed out'.format(template))
|
||||||
retry_timeout -= 1
|
retry_timeout -= 1
|
||||||
|
|
||||||
if retry_timeout >= 0:
|
if retry_timeout >= 0:
|
||||||
return True
|
return True, retry_timeout
|
||||||
|
|
||||||
raise Exception('{} timed out to much, skipping!')
|
raise Exception('{} timed out to much, skipping!')
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class S3HTTPRedirectHandler(HTTPRedirectHandler):
|
class S3HTTPRedirectHandler(HTTPRedirectHandler):
|
||||||
@@ -750,6 +757,8 @@ def filter_repositories(args, unfiltered_repositories):
|
|||||||
repositories = [r for r in repositories if name_regex.match(r['name'])]
|
repositories = [r for r in repositories if name_regex.match(r['name'])]
|
||||||
if args.skip_archived:
|
if args.skip_archived:
|
||||||
repositories = [r for r in repositories if not r.get('archived')]
|
repositories = [r for r in repositories if not r.get('archived')]
|
||||||
|
if args.exclude:
|
||||||
|
repositories = [r for r in repositories if r['name'] not in args.exclude]
|
||||||
|
|
||||||
return repositories
|
return repositories
|
||||||
|
|
||||||
@@ -790,7 +799,8 @@ def backup_repositories(args, output_directory, repositories):
|
|||||||
repo_dir,
|
repo_dir,
|
||||||
skip_existing=args.skip_existing,
|
skip_existing=args.skip_existing,
|
||||||
bare_clone=args.bare_clone,
|
bare_clone=args.bare_clone,
|
||||||
lfs_clone=args.lfs_clone)
|
lfs_clone=args.lfs_clone,
|
||||||
|
no_prune=args.no_prune)
|
||||||
|
|
||||||
if repository.get('is_gist'):
|
if repository.get('is_gist'):
|
||||||
# dump gist information to a file as well
|
# dump gist information to a file as well
|
||||||
@@ -807,8 +817,9 @@ def backup_repositories(args, output_directory, repositories):
|
|||||||
os.path.join(repo_cwd, 'wiki'),
|
os.path.join(repo_cwd, 'wiki'),
|
||||||
skip_existing=args.skip_existing,
|
skip_existing=args.skip_existing,
|
||||||
bare_clone=args.bare_clone,
|
bare_clone=args.bare_clone,
|
||||||
lfs_clone=args.lfs_clone)
|
lfs_clone=args.lfs_clone,
|
||||||
|
no_prune=args.no_prune
|
||||||
|
)
|
||||||
if args.include_issues or args.include_everything:
|
if args.include_issues or args.include_everything:
|
||||||
backup_issues(args, repo_cwd, repository, repos_template)
|
backup_issues(args, repo_cwd, repository, repos_template)
|
||||||
|
|
||||||
@@ -902,6 +913,8 @@ def backup_pulls(args, repo_cwd, repository, repos_template):
|
|||||||
pulls = {}
|
pulls = {}
|
||||||
_pulls_template = '{0}/{1}/pulls'.format(repos_template,
|
_pulls_template = '{0}/{1}/pulls'.format(repos_template,
|
||||||
repository['full_name'])
|
repository['full_name'])
|
||||||
|
_issue_template = '{0}/{1}/issues'.format(repos_template,
|
||||||
|
repository['full_name'])
|
||||||
query_args = {
|
query_args = {
|
||||||
'filter': 'all',
|
'filter': 'all',
|
||||||
'state': 'all',
|
'state': 'all',
|
||||||
@@ -941,10 +954,17 @@ def backup_pulls(args, repo_cwd, repository, repos_template):
|
|||||||
|
|
||||||
log_info('Saving {0} pull requests to disk'.format(
|
log_info('Saving {0} pull requests to disk'.format(
|
||||||
len(list(pulls.keys()))))
|
len(list(pulls.keys()))))
|
||||||
|
# Comments from pulls API are only _review_ comments
|
||||||
|
# regular comments need to be fetched via issue API.
|
||||||
|
# For backwards compatibility with versions <= 0.41.0
|
||||||
|
# keep name "comment_data" for review comments
|
||||||
|
comments_regular_template = _issue_template + '/{0}/comments'
|
||||||
comments_template = _pulls_template + '/{0}/comments'
|
comments_template = _pulls_template + '/{0}/comments'
|
||||||
commits_template = _pulls_template + '/{0}/commits'
|
commits_template = _pulls_template + '/{0}/commits'
|
||||||
for number, pull in list(pulls.items()):
|
for number, pull in list(pulls.items()):
|
||||||
if args.include_pull_comments or args.include_everything:
|
if args.include_pull_comments or args.include_everything:
|
||||||
|
template = comments_regular_template.format(number)
|
||||||
|
pulls[number]['comment_regular_data'] = retrieve_data(args, template)
|
||||||
template = comments_template.format(number)
|
template = comments_template.format(number)
|
||||||
pulls[number]['comment_data'] = retrieve_data(args, template)
|
pulls[number]['comment_data'] = retrieve_data(args, template)
|
||||||
if args.include_pull_commits or args.include_everything:
|
if args.include_pull_commits or args.include_everything:
|
||||||
@@ -1053,7 +1073,8 @@ def fetch_repository(name,
|
|||||||
local_dir,
|
local_dir,
|
||||||
skip_existing=False,
|
skip_existing=False,
|
||||||
bare_clone=False,
|
bare_clone=False,
|
||||||
lfs_clone=False):
|
lfs_clone=False,
|
||||||
|
no_prune=False):
|
||||||
if bare_clone:
|
if bare_clone:
|
||||||
if os.path.exists(local_dir):
|
if os.path.exists(local_dir):
|
||||||
clone_exists = subprocess.check_output(['git',
|
clone_exists = subprocess.check_output(['git',
|
||||||
@@ -1099,6 +1120,8 @@ def fetch_repository(name,
|
|||||||
git_command = ['git', 'lfs', 'fetch', '--all', '--prune']
|
git_command = ['git', 'lfs', 'fetch', '--all', '--prune']
|
||||||
else:
|
else:
|
||||||
git_command = ['git', 'fetch', '--all', '--force', '--tags', '--prune']
|
git_command = ['git', 'fetch', '--all', '--force', '--tags', '--prune']
|
||||||
|
if no_prune:
|
||||||
|
git_command.pop()
|
||||||
logging_subprocess(git_command, None, cwd=local_dir)
|
logging_subprocess(git_command, None, cwd=local_dir)
|
||||||
else:
|
else:
|
||||||
log_info('Cloning {0} repository from {1} to {2}'.format(
|
log_info('Cloning {0} repository from {1} to {2}'.format(
|
||||||
@@ -1106,16 +1129,19 @@ def fetch_repository(name,
|
|||||||
masked_remote_url,
|
masked_remote_url,
|
||||||
local_dir))
|
local_dir))
|
||||||
if bare_clone:
|
if bare_clone:
|
||||||
|
git_command = ['git', 'clone', '--mirror', remote_url, local_dir]
|
||||||
|
logging_subprocess(git_command, None)
|
||||||
if lfs_clone:
|
if lfs_clone:
|
||||||
git_command = ['git', 'lfs', 'clone', '--mirror', remote_url, local_dir]
|
git_command = ['git', 'lfs', 'fetch', '--all', '--prune']
|
||||||
else:
|
if no_prune:
|
||||||
git_command = ['git', 'clone', '--mirror', remote_url, local_dir]
|
git_command.pop()
|
||||||
|
logging_subprocess(git_command, None, cwd=local_dir)
|
||||||
else:
|
else:
|
||||||
if lfs_clone:
|
if lfs_clone:
|
||||||
git_command = ['git', 'lfs', 'clone', remote_url, local_dir]
|
git_command = ['git', 'lfs', 'clone', remote_url, local_dir]
|
||||||
else:
|
else:
|
||||||
git_command = ['git', 'clone', remote_url, local_dir]
|
git_command = ['git', 'clone', remote_url, local_dir]
|
||||||
logging_subprocess(git_command, None)
|
logging_subprocess(git_command, None)
|
||||||
|
|
||||||
|
|
||||||
def backup_account(args, output_directory):
|
def backup_account(args, output_directory):
|
||||||
|
|||||||
Reference in New Issue
Block a user