Skip to content

Commit a6bbb33

Browse files
committed
Merged in [18445] from rjsparks@nostrum.com:
Provide a management command to inform github backups. - Legacy-Id: 18455 Note: SVN reference [18445] has been migrated to Git commit 30ac983
2 parents 02bb72d + 30ac983 commit a6bbb33

2 files changed

Lines changed: 64 additions & 34 deletions

File tree

Lines changed: 63 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,74 @@
11
# Copyright The IETF Trust 2020, All Rights Reserved
22

3-
from django.core.management.base import BaseCommand
4-
from django.db.models import F
3+
4+
import github3
5+
6+
from collections import Counter
7+
from urllib.parse import urlparse
8+
9+
from django.conf import settings
10+
from django.core.management.base import BaseCommand, CommandError
511

612
from ietf.doc.models import DocExtResource
713
from ietf.group.models import GroupExtResource
814
from ietf.person.models import PersonExtResource
915

16+
# TODO: Think more about submodules. This currently will only take top level repos, with the assumption that the clone will include arguments to grab all the submodules.
17+
# As a consequence, we might end up pulling more than we need (or that the org or user expected)
18+
# Make sure this is what we want.
19+
1020
class Command(BaseCommand):
11-
help = ('Locate information about gihub repositories to backup')
21+
help = ('Locate information about github repositories to backup')
22+
23+
def add_arguments(self, parser):
24+
parser.add_argument('--verbose', dest='verbose', action='store_true', help='Show counts of types of repositories')
1225

1326
def handle(self, *args, **options):
1427

15-
info_dict = {}
16-
17-
18-
for repo in DocExtResource.objects.filter(name__slug='github_repo'):
19-
if not repo.value.endswith('/'):
20-
repo.value += '/'
21-
if repo not in info_dict:
22-
info_dict[repo.value] = []
23-
for username in DocExtResource.objects.filter(name__slug='github_username', doc=F('doc')):
24-
info_dict[repo.value].push(username.value)
25-
26-
for repo in GroupExtResource.objects.filter(name__slug='github_repo'):
27-
if not repo.value.endswith('/'):
28-
repo.value += '/'
29-
if repo not in info_dict:
30-
info_dict[repo.value] = []
31-
for username in GroupExtResource.objects.filter(name__slug='github_username', group=F('group')):
32-
info_dict[repo.value].push(username.value)
33-
34-
for repo in PersonExtResource.objects.filter(name__slug='github_repo'):
35-
if not repo.value.endswith('/'):
36-
repo.value += '/'
37-
if repo not in info_dict:
38-
info_dict[repo.value] = []
39-
for username in PersonExtResource.objects.filter(name__slug='github_username', person=F('person')):
40-
info_dict[repo.value].push(username.value)
41-
42-
#print (json.dumps(info_dict))
43-
# For now, all we need are the repo names
44-
for name in info_dict.keys():
45-
print(name)
28+
if not (hasattr(settings,'GITHUB_BACKUP_API_KEY') and settings.GITHUB_BACKUP_API_KEY):
29+
raise CommandError("ERROR: can't find GITHUB_BACKUP_API_KEY") # TODO: at >= py3.1, use returncode
30+
31+
github = github3.login(token = settings.GITHUB_BACKUP_API_KEY)
32+
owners = dict()
33+
repos = set()
34+
35+
for cls in (DocExtResource, GroupExtResource, PersonExtResource):
36+
for res in cls.objects.filter(name_id__in=('github_repo','github_org')):
37+
path_parts = urlparse(res.value).path.strip('/').split('/')
38+
if not path_parts or not path_parts[0]:
39+
continue
40+
41+
owner = path_parts[0]
42+
43+
if owner not in owners:
44+
try:
45+
gh_owner = github.user(username=owner)
46+
owners[owner] = gh_owner
47+
except github3.exceptions.NotFoundError:
48+
continue
49+
50+
if gh_owner.type in ('User', 'Organization'):
51+
if len(path_parts) > 1:
52+
repo = path_parts[1]
53+
if (owner, repo) not in repos:
54+
try:
55+
_ = github.repository(owner,repo)
56+
repos.add( (owner, repo) )
57+
except github3.exceptions.NotFoundError:
58+
continue
59+
else:
60+
for repo in github.repositories_by(owner):
61+
repos.add( (owner, repo.name) )
62+
63+
owner_types = Counter([owners[owner].type for owner in owners])
64+
if options['verbose']:
65+
self.stdout.write("Owners:")
66+
for key in owner_types:
67+
self.stdout.write(" %s: %s"%(key,owner_types[key]))
68+
self.stdout.write("Repositories: %d" % len(repos))
69+
for repo in sorted(repos):
70+
self.stdout.write(" https://github.com/%s/%s" % repo )
71+
else:
72+
for repo in sorted(repos):
73+
self.stdout.write("%s/%s" % repo )
74+

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ django-widget-tweaks>=1.4.2
2727
docutils>=0.12,!=0.15
2828
factory-boy>=2.9.0,<3
2929
Faker>=0.8.8,!=0.8.9,!=0.8.10 # from factory-boy # Faker 0.8.9,0.8.10 sometimes return string names instead of unicode.
30+
github3.py>=1.2
3031
hashids>=1.1.0
3132
html2text>=2019.8.11
3233
html5lib>=1.0.1

0 commit comments

Comments
 (0)