ghi 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.rdoc +180 -0
- data/Manifest.txt +14 -0
- data/README.rdoc +92 -0
- data/bin/ghi +6 -0
- data/lib/ghi.rb +55 -0
- data/lib/ghi/api.rb +106 -0
- data/lib/ghi/cli.rb +608 -0
- data/lib/ghi/issue.rb +29 -0
- data/spec/ghi/api_spec.rb +194 -0
- data/spec/ghi/cli_spec.rb +258 -0
- data/spec/ghi/issue_spec.rb +26 -0
- data/spec/ghi_spec.rb +91 -0
- metadata +70 -0
data/History.rdoc
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
=== 0.2.0 / 2009-11-03
|
2
|
+
|
3
|
+
* Major-minor release!
|
4
|
+
|
5
|
+
* Cleanup! (Better help, warnings and errors.)
|
6
|
+
|
7
|
+
|
8
|
+
=== 0.1.7 / 2009-08-26
|
9
|
+
|
10
|
+
* 2 bugfixes
|
11
|
+
|
12
|
+
* Allow dots in repo names.
|
13
|
+
* Fix bug preventing invocation from non-GitHub repo directories.
|
14
|
+
|
15
|
+
|
16
|
+
=== 0.1.6 / 2009-08-05
|
17
|
+
|
18
|
+
* 1 minor enhancement
|
19
|
+
|
20
|
+
* Support for non-"origin" remotes.
|
21
|
+
|
22
|
+
|
23
|
+
* 1 bugfix
|
24
|
+
|
25
|
+
* Graceful offline error.
|
26
|
+
|
27
|
+
|
28
|
+
=== 0.1.5 / 2009-07-08
|
29
|
+
|
30
|
+
* 2 bugfixes
|
31
|
+
|
32
|
+
* Long titles should wrap in show/verbose issue view.
|
33
|
+
* If a non-OptionParser argument fails early, re-parse when valid.
|
34
|
+
|
35
|
+
|
36
|
+
=== 0.1.4 / 2009-05-15
|
37
|
+
|
38
|
+
* 1 minor enhancement
|
39
|
+
|
40
|
+
* Minor Windows support.
|
41
|
+
|
42
|
+
|
43
|
+
=== 0.1.3 / 2009-05-08
|
44
|
+
|
45
|
+
* 1 minor enhancement
|
46
|
+
|
47
|
+
* Fix bug where `more' was being passed `less' options.
|
48
|
+
* Fix scoping of commands so `ghi user/repo` can run outside of a repo
|
49
|
+
directory.
|
50
|
+
|
51
|
+
|
52
|
+
=== 0.1.2 / 2009-05-07
|
53
|
+
|
54
|
+
* 1 major enhancement
|
55
|
+
|
56
|
+
* Better fallbacks. Enter `ghi open`, `ghi list closed`, `ghi search term`,
|
57
|
+
`ghi show 2`, `ghi user/repo`, etc., it will try to work. Fallbacks do not
|
58
|
+
accept options, though.
|
59
|
+
|
60
|
+
|
61
|
+
=== 0.1.1 / 2009-05-01
|
62
|
+
|
63
|
+
* 3 major enhancements
|
64
|
+
|
65
|
+
* Use `more' (or $GHI_PAGER) to accommodate lengthy output.
|
66
|
+
* Default to "-l" if Dir.pwd is a git repo.
|
67
|
+
* Accept numbered args/flags to shortcut "show" (e.g., "ghi -2", "ghi 2")
|
68
|
+
|
69
|
+
|
70
|
+
* 1 minor enhancement
|
71
|
+
|
72
|
+
* Update --url flag to GitHub's new convention.
|
73
|
+
|
74
|
+
|
75
|
+
=== 0.1.0 / 2009-04-27
|
76
|
+
|
77
|
+
* 2 major enhancements
|
78
|
+
|
79
|
+
* Use tempfiles when we should, the gitdir otherwise.
|
80
|
+
* Now a minor!
|
81
|
+
|
82
|
+
|
83
|
+
* 2 minor enhancement
|
84
|
+
|
85
|
+
* Small ANSI tweaks.
|
86
|
+
* Truncation fix.
|
87
|
+
|
88
|
+
|
89
|
+
=== 0.0.9 / 2009-04-27
|
90
|
+
|
91
|
+
* 1 major enhancement
|
92
|
+
|
93
|
+
* ANSI colors (honors your .gitconfig).
|
94
|
+
|
95
|
+
|
96
|
+
* 1 minor enhancement
|
97
|
+
|
98
|
+
* Bugfixes.
|
99
|
+
|
100
|
+
|
101
|
+
=== 0.0.8 / 2009-04-26
|
102
|
+
|
103
|
+
* 1 major enhancement
|
104
|
+
|
105
|
+
* Flag to return issues URLs.
|
106
|
+
|
107
|
+
|
108
|
+
* 1 minor enhancement
|
109
|
+
|
110
|
+
* Preliminary specs for top-level module and API class.
|
111
|
+
|
112
|
+
|
113
|
+
=== 0.0.7 / 2009-04-25
|
114
|
+
|
115
|
+
* 1 major enhancement
|
116
|
+
|
117
|
+
* Labels! Label and un-label at your whim.
|
118
|
+
|
119
|
+
|
120
|
+
* 1 minor enhancement
|
121
|
+
|
122
|
+
* Tail arguments are sometimes parsed. E.g., ghi -om "Issue message parsed".
|
123
|
+
|
124
|
+
|
125
|
+
=== 0.0.6 / 2009-04-25
|
126
|
+
|
127
|
+
* 2 minor enhancements
|
128
|
+
|
129
|
+
* Accept comments as arguments in more places.
|
130
|
+
* Update error message to accommodate both issues and comments.
|
131
|
+
|
132
|
+
|
133
|
+
=== 0.0.5 / 2009-04-25
|
134
|
+
|
135
|
+
* 3 major enhancements
|
136
|
+
|
137
|
+
* Flag to claim/label issues with your GitHub username (thanks, Jamie).
|
138
|
+
* Flag for commenting on issues.
|
139
|
+
* Prompt for GitHub login and token if absent from gitconfig.
|
140
|
+
|
141
|
+
|
142
|
+
* 1 minor enhancement
|
143
|
+
|
144
|
+
* Opening issues with a title bypasses your $EDITOR.
|
145
|
+
|
146
|
+
|
147
|
+
=== 0.0.4 / 2009-04-24
|
148
|
+
|
149
|
+
* 1 major enhancement
|
150
|
+
|
151
|
+
* Cache messages created in $EDITOR.
|
152
|
+
|
153
|
+
|
154
|
+
* 2 minor enhancements
|
155
|
+
|
156
|
+
* Refactoring and cleanup.
|
157
|
+
* Change editing messages.
|
158
|
+
|
159
|
+
|
160
|
+
=== 0.0.3 / 2009-04-23
|
161
|
+
|
162
|
+
* 2 minor enhancements
|
163
|
+
|
164
|
+
* Typo corrected.
|
165
|
+
* README updated.
|
166
|
+
|
167
|
+
|
168
|
+
=== 0.0.2 / 2009-04-22
|
169
|
+
|
170
|
+
* 1 major enhancement
|
171
|
+
|
172
|
+
* Add --search flag.
|
173
|
+
* Add --repo flag.
|
174
|
+
|
175
|
+
|
176
|
+
=== 0.0.1 / 2009-04-21
|
177
|
+
|
178
|
+
* 1 major enhancement
|
179
|
+
|
180
|
+
* Birthday!
|
data/Manifest.txt
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
= ghi
|
2
|
+
|
3
|
+
http://github.com/stephencelis/ghi
|
4
|
+
|
5
|
+
|
6
|
+
GitHub Issues on the command line. Use your <tt>$EDITOR</tt>, not your
|
7
|
+
browser.
|
8
|
+
|
9
|
+
== HOW?
|
10
|
+
|
11
|
+
Get:
|
12
|
+
|
13
|
+
% gem install stephencelis-ghi --source=http://gems.github.com
|
14
|
+
|
15
|
+
|
16
|
+
Go:
|
17
|
+
|
18
|
+
Usage: ghi [options]
|
19
|
+
-l, --list [state|term|number]
|
20
|
+
--search, --show
|
21
|
+
-v, --verbose
|
22
|
+
-o, --open [title|number]
|
23
|
+
--reopen
|
24
|
+
-c, --closed, --close [number]
|
25
|
+
-e, --edit [number]
|
26
|
+
-r, --repo, --repository [name]
|
27
|
+
-m, --comment [number|comment]
|
28
|
+
-t, --label [number] [label]
|
29
|
+
--claim [number]
|
30
|
+
-d, --unlabel [number] [label]
|
31
|
+
-u, --url [state|number]
|
32
|
+
--[no-]color
|
33
|
+
--[no-]pager
|
34
|
+
-V, --version
|
35
|
+
-h, --help
|
36
|
+
|
37
|
+
|
38
|
+
== EXAMPLE?
|
39
|
+
|
40
|
+
ghi works simply from within a repository. Some short examples:
|
41
|
+
|
42
|
+
ghi -l # Lists all open issues
|
43
|
+
ghi # Shorter shorthand for "ghi -l"
|
44
|
+
ghi -v # Lists all open issues, verbosely (includes body)
|
45
|
+
ghi -lc # Lists all closed issues
|
46
|
+
ghi -l "doesn't work" # Searches for open issues matching "doesn't work"
|
47
|
+
ghi -l invalid -c # Searches for closed issues matching "invalid"
|
48
|
+
ghi -l1 # Shows issue 1
|
49
|
+
ghi -1 # Shorter shorthand for "ghi -l1"
|
50
|
+
ghi 1 # Shorter shorthand still
|
51
|
+
ghi -o # Opens a new issue (in your $EDITOR)
|
52
|
+
ghi -o "New issue" # Opens a new issue with the title "New issue"
|
53
|
+
ghi -o "Title" -m "Body" # Opens a new issue with specified title and body
|
54
|
+
ghi -e1 # Edits issue number 1 (in your $EDITOR)
|
55
|
+
ghi -e1 -m "New body" # Edits issue number 1 with the specified body
|
56
|
+
ghi -c1 # Closes issue 1
|
57
|
+
ghi -c1 -m # Closes issue with comment (from your $EDITOR)
|
58
|
+
ghi -c1 -m "Comment" # Closes issue with specified comment
|
59
|
+
ghi -o1 # Reopens 1 (accepts comments, too)
|
60
|
+
ghi -m1 # Comments on issue 1 (in your $EDITOR)
|
61
|
+
ghi -t1 "tag" # Labels issue 1 with "tag"
|
62
|
+
ghi -d1 "tag" # Removes the label, "tag"
|
63
|
+
ghi --claim 1 # Tags issue 1 with your GitHub username
|
64
|
+
ghi -u # Loads issues in your browser.
|
65
|
+
ghi -u1 # Loads an issue in your browser.
|
66
|
+
|
67
|
+
|
68
|
+
ghi also works anywhere:
|
69
|
+
|
70
|
+
ghi -rghi # Your fork of "ghi"
|
71
|
+
ghi -rstephencelis/ghi # Mine: "stephencelis/ghi"
|
72
|
+
ghi stephencelis/ghi # Shorthand to merely list open.
|
73
|
+
|
74
|
+
|
75
|
+
ghi uses ANSI colors if you use them in git.
|
76
|
+
|
77
|
+
ghi looks for a <tt>$GHI_PAGER</tt> variable for paging.
|
78
|
+
|
79
|
+
|
80
|
+
== CONTRIBUTORS
|
81
|
+
|
82
|
+
* Jamie Macey (http://blog.tracefunc.com)
|
83
|
+
* Hiroshi Nakamura (http://github.com/nahi)
|
84
|
+
|
85
|
+
|
86
|
+
=== CONTRIBUTE?
|
87
|
+
|
88
|
+
ghi is not under currently under the control of any gem packaging system. To
|
89
|
+
build, use RubyGems:
|
90
|
+
|
91
|
+
% gem build ghi.gemspec
|
92
|
+
% sudo gem install ghi*.gem
|
data/bin/ghi
ADDED
data/lib/ghi.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "yaml"
|
3
|
+
|
4
|
+
module GHI
|
5
|
+
VERSION = "0.2"
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def login
|
9
|
+
return @login if defined? @login
|
10
|
+
@login = `git config --get github.user`.chomp
|
11
|
+
if @login.empty?
|
12
|
+
begin
|
13
|
+
print "Please enter your GitHub username: "
|
14
|
+
@login = gets.chomp
|
15
|
+
valid = user? @login
|
16
|
+
warn "invalid username" unless valid
|
17
|
+
end until valid
|
18
|
+
`git config --global github.user #@login`
|
19
|
+
end
|
20
|
+
@login
|
21
|
+
end
|
22
|
+
|
23
|
+
def token
|
24
|
+
return @token if defined? @token
|
25
|
+
@token = `git config --get github.token`.chomp
|
26
|
+
if @token.empty?
|
27
|
+
begin
|
28
|
+
print "GitHub token (https://github.com/account): "
|
29
|
+
@token = gets.chomp
|
30
|
+
valid = token? @token
|
31
|
+
warn "invalid token for #{login}" unless valid
|
32
|
+
end until valid
|
33
|
+
`git config --global github.token #@token`
|
34
|
+
end
|
35
|
+
@token
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def user?(username)
|
41
|
+
url = "http://github.com/api/v2/yaml/user/show/#{username}"
|
42
|
+
!YAML.load(Net::HTTP.get(URI.parse(url)))["user"].nil?
|
43
|
+
rescue ArgumentError, URI::InvalidURIError
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
def token?(token)
|
48
|
+
url = "http://github.com/api/v2/yaml/user/show/#{login}"
|
49
|
+
url += "?login=#{login}&token=#{token}"
|
50
|
+
!YAML.load(Net::HTTP.get(URI.parse(url)))["user"]["plan"].nil?
|
51
|
+
rescue ArgumentError, NoMethodError, URI::InvalidURIError
|
52
|
+
false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/ghi/api.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "yaml"
|
3
|
+
|
4
|
+
class GHI::API
|
5
|
+
class InvalidRequest < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
class InvalidConnection < StandardError
|
9
|
+
end
|
10
|
+
|
11
|
+
class ResponseError < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
API_URL = "http://github.com/api/v2/yaml/issues/:action/:user/:repo"
|
15
|
+
|
16
|
+
attr_reader :user, :repo
|
17
|
+
|
18
|
+
def initialize(user, repo)
|
19
|
+
raise InvalidConnection if user.nil? || repo.nil?
|
20
|
+
@user, @repo = user, repo
|
21
|
+
end
|
22
|
+
|
23
|
+
def search(term, state = :open)
|
24
|
+
get(:search, state, term)["issues"].map { |attrs| GHI::Issue.new(attrs) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def list(state = :open)
|
28
|
+
get(:list, state)["issues"].map { |attrs| GHI::Issue.new(attrs) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def show(number)
|
32
|
+
GHI::Issue.new get(:show, number)["issue"]
|
33
|
+
end
|
34
|
+
|
35
|
+
def open(title, body)
|
36
|
+
GHI::Issue.new post(:open, :title => title, :body => body)["issue"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def edit(number, title, body)
|
40
|
+
res = post :edit, number, :title => title, :body => body
|
41
|
+
GHI::Issue.new res["issue"]
|
42
|
+
end
|
43
|
+
|
44
|
+
def close(number)
|
45
|
+
GHI::Issue.new post(:close, number)["issue"]
|
46
|
+
end
|
47
|
+
|
48
|
+
def reopen(number)
|
49
|
+
GHI::Issue.new post(:reopen, number)["issue"]
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_label(label, number)
|
53
|
+
post("label/add", label, number)["labels"]
|
54
|
+
end
|
55
|
+
|
56
|
+
def remove_label(label, number)
|
57
|
+
post("label/remove", label, number)["labels"]
|
58
|
+
end
|
59
|
+
|
60
|
+
def comment(number, comment)
|
61
|
+
post(:comment, number, :comment => comment)["comment"]
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def get(*args)
|
67
|
+
res = YAML.load Net::HTTP.get(URI.parse(url(*args) + auth(true)))
|
68
|
+
raise ResponseError, errors(res) if res["error"]
|
69
|
+
res
|
70
|
+
rescue ArgumentError, URI::InvalidURIError
|
71
|
+
raise ResponseError, "GitHub hiccuped on your request"
|
72
|
+
rescue SocketError
|
73
|
+
raise ResponseError, "couldn't find the internet"
|
74
|
+
end
|
75
|
+
|
76
|
+
def post(*args)
|
77
|
+
params = args.last.is_a?(Hash) ? args.pop : {}
|
78
|
+
params.update auth
|
79
|
+
res = YAML.load Net::HTTP.post_form(URI.parse(url(*args)), params).body
|
80
|
+
raise ResponseError, errors(res) if res["error"]
|
81
|
+
res
|
82
|
+
rescue ArgumentError, URI::InvalidURIError
|
83
|
+
raise ResponseError, "GitHub hiccuped on your request"
|
84
|
+
rescue SocketError
|
85
|
+
raise ResponseError, "couldn't find the internet"
|
86
|
+
end
|
87
|
+
|
88
|
+
def errors(response)
|
89
|
+
[*response["error"]].map { |e| e["error"] } * ", "
|
90
|
+
end
|
91
|
+
|
92
|
+
def auth(query = false)
|
93
|
+
if query
|
94
|
+
"?login=#{GHI.login}&token=#{GHI.token}"
|
95
|
+
else
|
96
|
+
{ :login => GHI.login, :token => GHI.token }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def url(action, *args)
|
101
|
+
@url ||= API_URL.sub(":user", user).sub(":repo", repo)
|
102
|
+
uri = @url.sub ":action", action.to_s
|
103
|
+
uri += "/#{args.join("/")}" unless args.empty?
|
104
|
+
uri
|
105
|
+
end
|
106
|
+
end
|