octonaut 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.md +20 -0
- data/README.md +184 -0
- data/Rakefile +8 -0
- data/bin/octonaut +4 -0
- data/lib/octonaut.rb +66 -0
- data/lib/octonaut/commands/common.rb +19 -0
- data/lib/octonaut/commands/repositories.rb +42 -0
- data/lib/octonaut/commands/users.rb +88 -0
- data/lib/octonaut/helpers.rb +20 -0
- data/lib/octonaut/printer.rb +31 -0
- data/lib/octonaut/printers/organizations.rb +37 -0
- data/lib/octonaut/printers/repositories.rb +49 -0
- data/lib/octonaut/printers/users.rb +41 -0
- data/lib/octonaut/version.rb +3 -0
- data/octonaut.gemspec +32 -0
- data/spec/fixtures/.netrc +2 -0
- data/spec/fixtures/languages.json +10 -0
- data/spec/fixtures/languages.table +8 -0
- data/spec/fixtures/repositories.json +2522 -0
- data/spec/fixtures/repositories.ls +30 -0
- data/spec/fixtures/repository.json +85 -0
- data/spec/fixtures/user.json +42 -0
- data/spec/fixtures/users.json +542 -0
- data/spec/fixtures/users.ls +30 -0
- data/spec/octonaut_spec.rb +69 -0
- data/spec/repositories_spec.rb +56 -0
- data/spec/spec_helper.rb +90 -0
- data/spec/users_spec.rb +138 -0
- metadata +265 -0
data/LICENSE.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Wynn Netherland
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
# Octonaut
|
2
|
+
|
3
|
+
A little CLI sugar for the GitHub API, built with [gli][] and [Octokit][].
|
4
|
+
|
5
|
+
**Still early. Rapidly evolving.** Why not [help out][contributing]?
|
6
|
+
|
7
|
+
### Why not `hub`?
|
8
|
+
|
9
|
+
[hub][] is great, you should use it. But hub focuses mostly on smoothing the
|
10
|
+
git workflow for GitHub and most commands are in the context of a GitHub
|
11
|
+
repository.
|
12
|
+
|
13
|
+
Octonaut is more general purpose CLI for the GitHub API. Oh and [plugins][].
|
14
|
+
|
15
|
+
### Installation
|
16
|
+
|
17
|
+
Install via Rubygems:
|
18
|
+
|
19
|
+
```
|
20
|
+
gem install octonaut
|
21
|
+
```
|
22
|
+
|
23
|
+
### Example usage
|
24
|
+
```
|
25
|
+
$ octonaut
|
26
|
+
NAME
|
27
|
+
octonaut - Octokit-powered CLI for GitHub
|
28
|
+
|
29
|
+
SYNOPSIS
|
30
|
+
octonaut [global options] command [command options] [arguments...]
|
31
|
+
|
32
|
+
GLOBAL OPTIONS
|
33
|
+
-a, --[no-]auto_traversal - Automatically fetch all pages of paginated results
|
34
|
+
--help - Show this message
|
35
|
+
-n, --[no-]netrc - Use .netrc file for authentication
|
36
|
+
-p, --password=arg - GitHub password (default: ********)
|
37
|
+
-t, --oauth_token, --token=arg - GitHub API token (default: ********)
|
38
|
+
-u, --login=arg - GitHub login (default: none)
|
39
|
+
|
40
|
+
COMMANDS
|
41
|
+
browse - Browse resource on github.com
|
42
|
+
follow - Follow a user
|
43
|
+
followers - View followers for a user
|
44
|
+
following - View who a user is following
|
45
|
+
follows - Check to see if a user follows another
|
46
|
+
help - Shows a list of commands or help for one command
|
47
|
+
langs, languages - Display languages for a repo
|
48
|
+
me - View your profile
|
49
|
+
repo, repository - Display details for a repository
|
50
|
+
repos, repositories - List repositories for a user or organization
|
51
|
+
say - An plugin method
|
52
|
+
unfollow - Unfollow a user
|
53
|
+
user, whois - View profile for a user
|
54
|
+
```
|
55
|
+
|
56
|
+
View a user's profile:
|
57
|
+
|
58
|
+
```
|
59
|
+
$ octonaut whois cloudhead
|
60
|
+
ID 40774
|
61
|
+
JOINED 2008-12-16T15:09:49Z
|
62
|
+
LOGIN cloudhead
|
63
|
+
NAME Alexis Sellier
|
64
|
+
COMPANY SoundCloud, Ltd.
|
65
|
+
LOCATION Berlin
|
66
|
+
FOLLOWERS 2347
|
67
|
+
FOLLOWING 48
|
68
|
+
HIREABLE true
|
69
|
+
URL http://twitter.com/cloudhead
|
70
|
+
```
|
71
|
+
|
72
|
+
Browse a user on github.com in your default browser:
|
73
|
+
|
74
|
+
```
|
75
|
+
$ octonaut browse cloudhead
|
76
|
+
```
|
77
|
+
|
78
|
+
List followers:
|
79
|
+
```
|
80
|
+
$ octonaut followers pengwynn
|
81
|
+
krisbulman
|
82
|
+
camdub
|
83
|
+
cglee
|
84
|
+
nextmat
|
85
|
+
zachinglis
|
86
|
+
seaofclouds
|
87
|
+
njonsson
|
88
|
+
davidnorth
|
89
|
+
polomasta
|
90
|
+
webiest
|
91
|
+
mchelen
|
92
|
+
brogers
|
93
|
+
marclove
|
94
|
+
adamstac
|
95
|
+
marshall
|
96
|
+
asenchi
|
97
|
+
piyush
|
98
|
+
rmetzler
|
99
|
+
nileshtrivedi
|
100
|
+
sferik
|
101
|
+
jimmybaker
|
102
|
+
jnunemaker
|
103
|
+
peterberkenbosch
|
104
|
+
leah
|
105
|
+
jakestutzman
|
106
|
+
nkabbara
|
107
|
+
etagwerker
|
108
|
+
vagostino
|
109
|
+
johan--
|
110
|
+
bry4n
|
111
|
+
...
|
112
|
+
```
|
113
|
+
|
114
|
+
Follow a user:
|
115
|
+
```
|
116
|
+
$ octonaut follow linus
|
117
|
+
Followed linus.
|
118
|
+
```
|
119
|
+
|
120
|
+
Unfollow a user:
|
121
|
+
```
|
122
|
+
$ octonaut unfollow pengwynn
|
123
|
+
Unfollowed pengwynn.
|
124
|
+
```
|
125
|
+
|
126
|
+
## Extend with plugins
|
127
|
+
|
128
|
+
Octonaut makes it simple to extend the CLI with new commands just by adding
|
129
|
+
some Ruby files to `~/.octonaut/plugins`:
|
130
|
+
|
131
|
+
```
|
132
|
+
$ cat ~/.octonaut/plugins/test.rb
|
133
|
+
module Octonaut
|
134
|
+
|
135
|
+
desc 'An plugin method'
|
136
|
+
arg_name 'text'
|
137
|
+
command :say do |c|
|
138
|
+
c.action do |global,options,args|
|
139
|
+
puts @client.say args.shift
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
$ octonaut say "hello from plugins"
|
145
|
+
|
146
|
+
MMM. .MMM
|
147
|
+
MMMMMMMMMMMMMMMMMMM
|
148
|
+
MMMMMMMMMMMMMMMMMMM ____________________
|
149
|
+
MMMMMMMMMMMMMMMMMMMMM | |
|
150
|
+
MMMMMMMMMMMMMMMMMMMMMMM | hello from plugins |
|
151
|
+
MMMMMMMMMMMMMMMMMMMMMMMM |_ ________________|
|
152
|
+
MMMM::- -:::::::- -::MMMM |/
|
153
|
+
MM~:~ ~:::::~ ~:~MM
|
154
|
+
.. MMMMM::. .:::+:::. .::MMMMM ..
|
155
|
+
.MM::::: ._. :::::MM.
|
156
|
+
MMMM;:::::;MMMM
|
157
|
+
-MM MMMMMMM
|
158
|
+
^ M+ MMMMMMMMM
|
159
|
+
MMMMMMM MM MM MM
|
160
|
+
MM MM MM MM
|
161
|
+
MM MM MM MM
|
162
|
+
.~~MM~MM~MM~MM~~.
|
163
|
+
~~~~MM:~MM~~~MM~:MM~~~~
|
164
|
+
~~~~~~==~==~~~==~==~~~~~~
|
165
|
+
~~~~~~==~==~==~==~~~~~~
|
166
|
+
:~==~==~==~==~~
|
167
|
+
```
|
168
|
+
|
169
|
+
## Inspiration
|
170
|
+
|
171
|
+
Octonaut is inspired by [`t`, the awesome Twitter CLI][t] from [Erik Michaels-Ober][sferik].
|
172
|
+
|
173
|
+
## Copyright
|
174
|
+
|
175
|
+
Copyright (c) 2013 Wynn Netherland. See [LICENSE][] for details.
|
176
|
+
|
177
|
+
[hub]: https://github.com/defunkt/hub
|
178
|
+
[gli]: https://github.com/davetron5000/gli
|
179
|
+
[octokit]: https://github.com/pengwynn/octokit
|
180
|
+
[plugins]: #extend-with-plugins
|
181
|
+
[contributing]: https://github.com/pengwynn/octonaut/blob/master/CONTRIBUTING.md
|
182
|
+
[t]: https://github.com/sferik/t
|
183
|
+
[sferik]: https://github.com/sferik
|
184
|
+
[LICENSE]: https://github.com/pengwynn/octonaut/blob/master/LICENSE.md
|
data/Rakefile
ADDED
data/bin/octonaut
ADDED
data/lib/octonaut.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'csv'
|
2
|
+
require 'gli'
|
3
|
+
require 'launchy'
|
4
|
+
require 'octokit'
|
5
|
+
require 'octonaut/printer'
|
6
|
+
require 'octonaut/helpers'
|
7
|
+
require 'octonaut/version'
|
8
|
+
|
9
|
+
module Octonaut
|
10
|
+
extend GLI::App
|
11
|
+
extend Octonaut::Printer
|
12
|
+
extend Octonaut::Helpers
|
13
|
+
|
14
|
+
program_desc 'Octokit-powered CLI for GitHub'
|
15
|
+
commands_from 'octonaut/commands'
|
16
|
+
commands_from File.join(ENV['HOME'], '.octonaut', 'plugins')
|
17
|
+
|
18
|
+
|
19
|
+
desc 'Use .netrc file for authentication'
|
20
|
+
default_value false
|
21
|
+
switch [:n, :netrc]
|
22
|
+
|
23
|
+
desc 'GitHub login'
|
24
|
+
flag [:u, :login]
|
25
|
+
desc 'GitHub password'
|
26
|
+
flag [:p, :password], :mask => true
|
27
|
+
desc 'GitHub API token'
|
28
|
+
flag [:t, :oauth_token, :token], :mask => true
|
29
|
+
desc 'Automatically fetch all pages of paginated results'
|
30
|
+
switch [:a, :auto_traversal]
|
31
|
+
|
32
|
+
|
33
|
+
pre do |global,command,options,args|
|
34
|
+
# Pre logic here
|
35
|
+
# Return true to proceed; false to abourt and not call the
|
36
|
+
# chosen command
|
37
|
+
# Use skips_pre before a command to skip this block
|
38
|
+
# on that command only
|
39
|
+
|
40
|
+
@client = client(global, options)
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
post do |global,command,options,args|
|
45
|
+
# Post logic here
|
46
|
+
# Use skips_post before a command to skip this
|
47
|
+
# block on that command only
|
48
|
+
end
|
49
|
+
|
50
|
+
on_error do |exception|
|
51
|
+
case exception
|
52
|
+
when Octokit::Unauthorized
|
53
|
+
puts "Authentication required. Please check your login, password, or token."
|
54
|
+
else
|
55
|
+
# Need to handle other return codes within the calling method
|
56
|
+
true
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.client(global, options)
|
61
|
+
opts = global.merge(options).
|
62
|
+
select {|k, v| Octokit::Configuration::VALID_OPTIONS_KEYS.include?(k) }
|
63
|
+
Octokit::Client.new(opts)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Octonaut
|
2
|
+
desc 'Browse resource on github.com'
|
3
|
+
arg_name 'name'
|
4
|
+
command :browse do |c|
|
5
|
+
c.action do |global,options,args|
|
6
|
+
name = args.shift
|
7
|
+
raise ArgumentError.new("Name required") if name.nil?
|
8
|
+
|
9
|
+
owner, repo = name.split("/")
|
10
|
+
if repo.nil?
|
11
|
+
item = @client.user owner
|
12
|
+
else
|
13
|
+
item = @client.repo(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
Octonaut.open item
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Octonaut
|
2
|
+
|
3
|
+
desc "Display details for a repository"
|
4
|
+
arg_name 'name'
|
5
|
+
command [:repo, :repository] do |c|
|
6
|
+
c.action do |global,options,args|
|
7
|
+
name = args.shift
|
8
|
+
|
9
|
+
print_repo_table @client.repo(name)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "List repositories for a user or organization"
|
14
|
+
arg_name 'login', :optional
|
15
|
+
command [:repos, :repositories] do |c|
|
16
|
+
c.desc "Filter repos by type: all, owner, member, public, private"
|
17
|
+
c.flag :type
|
18
|
+
|
19
|
+
c.desc "Sort repos by: created, updated, pushed, full_name"
|
20
|
+
c.flag :sort
|
21
|
+
|
22
|
+
c.desc "Sort direction: asc or desc"
|
23
|
+
c.flag :direction
|
24
|
+
|
25
|
+
c.action do |global,options,args|
|
26
|
+
login = args.shift
|
27
|
+
opts = options.select {|k,v| !v.nil? }
|
28
|
+
|
29
|
+
ls_repos @client.repositories(login, opts)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Display languages for a repo"
|
34
|
+
arg_name "owner/repo"
|
35
|
+
command [:langs, :languages] do |c|
|
36
|
+
c.action do |global,options,args|
|
37
|
+
name = args.shift
|
38
|
+
|
39
|
+
print_table @client.languages(name)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Octonaut
|
2
|
+
desc "View your profile"
|
3
|
+
command :me do |c|
|
4
|
+
c.action do |global,options,args|
|
5
|
+
user = @client.user
|
6
|
+
print_user_table user
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "View profile for a user"
|
11
|
+
arg_name 'login'
|
12
|
+
command [:user, :whois] do |c|
|
13
|
+
c.action do |global,options,args|
|
14
|
+
login = args.shift
|
15
|
+
begin
|
16
|
+
user = @client.user login
|
17
|
+
case user['type']
|
18
|
+
when 'Organization'
|
19
|
+
print_org_table user
|
20
|
+
else
|
21
|
+
print_user_table user
|
22
|
+
end
|
23
|
+
rescue Octokit::NotFound
|
24
|
+
puts "User or organization #{login} not found"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "View followers for a user"
|
30
|
+
arg_name 'login', :optional
|
31
|
+
command :followers do |c|
|
32
|
+
c.action do |global,options,args|
|
33
|
+
login = args.shift || @client.login
|
34
|
+
print_users @client.followers(login), options
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "View who a user is following"
|
39
|
+
arg_name 'login', :optional
|
40
|
+
command :following do |c|
|
41
|
+
c.action do |global,options,args|
|
42
|
+
login = args.shift || @client.login
|
43
|
+
print_users @client.following(login), options
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
desc "Check to see if a user follows another"
|
48
|
+
arg_name 'target'
|
49
|
+
command :follows do |c|
|
50
|
+
c.action do |global,options,args|
|
51
|
+
target = args.shift
|
52
|
+
message = if @client.follows?(target)
|
53
|
+
"Yes, #{@client.login} follows #{target}."
|
54
|
+
else
|
55
|
+
"No, #{@client.login} does not follow #{target}."
|
56
|
+
end
|
57
|
+
|
58
|
+
puts message
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
desc "Follow a user"
|
63
|
+
arg_name 'target', :multiple
|
64
|
+
command :follow do |c|
|
65
|
+
c.action do |global,options,args|
|
66
|
+
targets = args
|
67
|
+
targets.each {|t| follow_user(t) }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "Unfollow a user"
|
72
|
+
arg_name 'target', :multiple
|
73
|
+
command :unfollow do |c|
|
74
|
+
c.action do |global,options,args|
|
75
|
+
targets = args
|
76
|
+
targets.each {|t| unfollow_user(t) }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.follow_user(target)
|
81
|
+
puts "Followed #{target}." if @client.follow(target)
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.unfollow_user(target)
|
85
|
+
puts "Unfollowed #{target}." if @client.unfollow(target)
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Octonaut
|
2
|
+
module Helpers
|
3
|
+
|
4
|
+
def open(resource, relation = 'html')
|
5
|
+
link_field = case relation
|
6
|
+
when 'self'
|
7
|
+
'url'
|
8
|
+
when /_url$/
|
9
|
+
relation
|
10
|
+
else
|
11
|
+
"#{relation}_url"
|
12
|
+
end
|
13
|
+
|
14
|
+
url = resource.send(link_field.to_sym)
|
15
|
+
|
16
|
+
Launchy.open url
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|