Skip to content

Commit a02fabe

Browse files
committed
added initial authentication and repo commands
1 parent 731e5ac commit a02fabe

6 files changed

Lines changed: 235 additions & 12 deletions

File tree

Makefile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ register:
2424

2525
publish:
2626
python setup.py sdist upload
27-
28-
29-
27+
28+
# Run as `make ARGS="--version" debug`
29+
debug:
30+
PYTHONPATH="${PYTHONPATH}:./src" python -m pdb src/githubflow/runner.py $(ARGS)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
url='http://github.com/Demandcube/github-flow',
3030
include_package_data=True,
3131
install_requires=[
32-
'Click',
32+
'Click','requests', 'tabulate',
3333
],
3434
entry_points='''
3535
[console_scripts]

src/githubflow/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
__version__ = '0.2.1'
1+
__version__ = '0.3'
22
__author__ = 'Steve Morin'

src/githubflow/authenticate.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# get token
2+
# if not token
3+
# request username and password
4+
# get token
5+
# save token to file
6+
7+
import ConfigParser
8+
import os.path
9+
import requests
10+
11+
auth_section = 'authentication'
12+
13+
def getToken(ini_file,debug=False):
14+
result = None
15+
try:
16+
config = ConfigParser.RawConfigParser()
17+
config.read(os.path.expanduser(ini_file))
18+
result = config.get(auth_section,'token')
19+
except Exception, e:
20+
if debug:
21+
print e
22+
finally:
23+
return result
24+
25+
def createToken(username,password):
26+
r = requests.post('https://api.github.com/authorizations', auth=(username, password), data='{"scopes": ["repo"], "note": "github-flow token"}')
27+
if r.status_code == 201:
28+
return r.json()['token']
29+
elif r.status_code == 401:
30+
print "Error:"+r.json()['message']
31+
else:
32+
print r.text
33+
34+
def saveToken(ini_file,token):
35+
config = ConfigParser.SafeConfigParser()
36+
config.add_section(auth_section)
37+
config.set(auth_section, 'token', token)
38+
39+
# Writing our configuration file to 'example.cfg'
40+
with open(os.path.expanduser(ini_file), 'w+b') as configfile:
41+
config.write(configfile)

src/githubflow/github.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import click
2+
import requests
3+
from tabulate import tabulate
4+
5+
class github:
6+
def __init__(self,ghf):
7+
self.ghf=ghf
8+
9+
# def repos(self,org):
10+
# if self.ghf.debug: click.echo("org:"+org+" token:"+self.ghf.token)
11+
# url='https://api.github.com/orgs/'+org+'/repos'
12+
# headers=self.get_auth_header()
13+
# data=''
14+
# r = requests.get(url, headers=headers, data=data)
15+
# fields = ['full_name']
16+
# if len(self.ghf.fields) > 0:
17+
# fields = self.ghf.fields
18+
# if self.ghf.profile:
19+
# self.profile_keys(r.json())
20+
# else:
21+
# self.print_object_array_with_fields(r.json(),fields)
22+
23+
def repos(self,org):
24+
url='https://api.github.com/orgs/'+org+'/repos'
25+
fields = ['full_name']
26+
headers=self.get_auth_header()
27+
self.make_github_get_request(fields,url,headers)
28+
29+
30+
def make_github_get_request(self,default_fields,url,headers,data=''):
31+
if self.ghf.debug: click.echo("url:"+url+" token:"+self.ghf.token+" fields:"+",".join(default_fields))
32+
r = requests.get(url, headers=headers, data=data)
33+
fields = default_fields
34+
if len(self.ghf.fields) > 0:
35+
fields = self.ghf.fields
36+
table = []
37+
if self.ghf.profile:
38+
(fields,table) = self.get_profile_table(r.json())
39+
else:
40+
table = self.get_table_from_object_array_with_fields(fields,r.json())
41+
self.print_table(fields,table)
42+
43+
def print_table(self, field_names, table):
44+
if self.ghf.export_csv:
45+
separator = self.ghf.csv_separator
46+
if self.ghf.print_header_row:
47+
click.echo(separator.join(field_names))
48+
for entry in table:
49+
click.echo(separator.join(entry))
50+
else:
51+
if self.ghf.print_header_row:
52+
click.echo(tabulate(table, field_names, tablefmt="simple"))
53+
else:
54+
click.echo(tabulate(table, tablefmt="simple"))
55+
56+
def test_post(self,url,headers,data):
57+
r = requests.post(url, headers=headers, data=data)
58+
if r.status_code == 201:
59+
click.echo(r.json())
60+
elif r.status_code == 401:
61+
click.echo("Error:"+r.json()['message'])
62+
else:
63+
click.echo('status:'+str(r.status_code))
64+
click.echo(r.text)
65+
66+
def test_get(self,url,headers,data):
67+
r = requests.get(url, headers=headers, data=data)
68+
if r.status_code == 201:
69+
click.echo(r.json())
70+
elif r.status_code == 401:
71+
click.echo("Error:"+r.json()['message'])
72+
else:
73+
click.echo('status:'+str(r.status_code))
74+
click.echo(r.text)
75+
76+
77+
def get_auth_header(self):
78+
headers={'Authorization' : 'token '+self.ghf.token}
79+
return headers
80+
81+
82+
83+
def get_profile_table(self,json):
84+
outter_key_hash = {}
85+
inner_key_hash = {}
86+
if type(json) == type([]):
87+
for item in json:
88+
if type(item) == type(u''):
89+
outter_key_hash[item] = 1 if item not in outter_key_hash else outter_key_hash[item] + 1
90+
if type(item) == type({}):
91+
for inner_item in item:
92+
if type(inner_item) == type(u''):
93+
inner_key_hash[inner_item] = 1 if inner_item not in inner_key_hash else inner_key_hash[inner_item] + 1
94+
# elif type(json) == type({}):
95+
# None
96+
table = []
97+
for key, value in outter_key_hash.items():
98+
table.append(['level1',key,str(value)])
99+
for key, value in inner_key_hash.items():
100+
table.append(['level2',key,str(value)])
101+
field_names = ['level', 'name','count']
102+
table = sorted(table, key=lambda key: key[1])
103+
return (field_names,table)
104+
# click.echo(tabulate(table, field_names, tablefmt="simple"))
105+
106+
def get_table_from_object_array_with_fields(self,fields,json):
107+
table = []
108+
if type(json) == type([]):
109+
for item in json:
110+
if type(item) == type({}):
111+
row = []
112+
for field in fields:
113+
if field in item:
114+
row.append(item[field])
115+
else:
116+
row.append('')
117+
table.append(row)
118+
headers = fields
119+
return table
120+
# click.echo(tabulate(table, headers, tablefmt="simple"))
121+
122+
123+
# >>> js = ['name1', 'name2', {'iname1':11,'iname2':12}]
124+
# >>> for item in js:
125+
# ... print type(item)
126+
# ...
127+
# <type 'str'>
128+
# <type 'str'>
129+
# <type 'dict'>

src/githubflow/runner.py

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import click
2+
import sys
23

3-
from githubflow import __version__
4-
4+
from githubflow import __version__, authenticate, github
55

66
def print_version(ctx, value):
77
if not value:
@@ -10,10 +10,62 @@ def print_version(ctx, value):
1010
ctx.exit()
1111

1212

13-
@click.command()
14-
@click.option('--version', is_flag=True, callback=print_version,expose_value=False, is_eager=True)
15-
def cli():
16-
"""Example script."""
17-
click.echo('Hello World!')
13+
class ghf(object):
14+
def __init__(self, ini_file, debug, token, username, password, profile, fields, print_header_row, export_csv, csv_separator):
15+
self.debug = debug
16+
self.token = token
17+
self.profile = profile
18+
self.fields=fields
19+
self.print_header_row=print_header_row
20+
self.export_csv=export_csv
21+
self.csv_separator=csv_separator
22+
if token == None:
23+
token = authenticate.getToken(ini_file,debug)
24+
self.token = token
25+
if token == None:
26+
if username == None:
27+
click.echo("Username is required to create your access token")
28+
sys.exit()
29+
if password == None:
30+
password = click.prompt('password', hide_input=True, confirmation_prompt=True)
31+
if debug: click.echo(password)
32+
token = authenticate.createToken(username,password)
33+
if token == None:
34+
click.echo('Problem getting your github authentication token')
35+
sys.exit(1)
36+
authenticate.saveToken(ini_file,token)
37+
self.token = token
38+
39+
40+
41+
@click.group()
42+
@click.option('--ini-file', envvar='GHF_INI_FILE', default='~/.ghf.ini', help='which config file to read/write authentication token')
43+
@click.option('--debug/--no-debug', default=False, envvar='GHF_DEBUG', help='turn on/off debug mode')
44+
@click.option('--version', is_flag=True, callback=print_version,expose_value=False, is_eager=True, help='print programs version')
45+
@click.option('--username', '-u', envvar="GHF_USERNAME", default=None, help='github username used to create authentication token')
46+
@click.option('--password', '-p', envvar="GHF_PASSWORD", default=None, help='github password used to create authentication token')
47+
@click.option('--token', '-t', envvar="GHF_TOKEN", default=None, help='explicitly pass in your authentication token')
48+
@click.option('--profile', is_flag=True, default=False, envvar="GHF_PROFILE", help='print out the fields from the return github json object')
49+
@click.option('--fields', '-f', multiple=True, default=(), help='select these fields in your output')
50+
@click.option('--header/--no-header', is_flag=True, default=True, envvar="GHF_HEADER", help='print or don\'t print the header row')
51+
@click.option('--csv', is_flag=True, default=False, envvar="GHF_CSV", help='output data as csv')
52+
@click.option('--csv-separator', default=',', envvar="GHF_CSV_SEPARATOR", help='set the csv separator')
53+
@click.pass_context
54+
def cli(ctx, ini_file, debug, token, username, password, profile, fields, header, csv, csv_separator):
55+
ctx.obj = ghf(ini_file, debug, token, username, password, profile, fields, header, csv, csv_separator)
56+
57+
# click.prompt('password', hide_input=True, confirmation_prompt=True)
58+
59+
@cli.command()
60+
@click.argument('org')
61+
@click.pass_obj
62+
def repos(ghf, org):
63+
"""List all the repos"""
64+
# click.echo('list repos:'+str(ghf.token))
65+
gh = github.github(ghf)
66+
gh.repos(org)
67+
68+
if __name__ == '__main__':
69+
cli()
1870

1971

0 commit comments

Comments
 (0)