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.
@@ -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!
@@ -0,0 +1,14 @@
1
+ History.rdoc
2
+ Manifest.txt
3
+ MIT-LICENSE
4
+ Rakefile
5
+ README.rdoc
6
+ bin/ghi
7
+ lib/ghi/api.rb
8
+ lib/ghi/cli.rb
9
+ lib/ghi/issue.rb
10
+ lib/ghi.rb
11
+ spec/ghi/api_spec.rb
12
+ spec/ghi/cli_spec.rb
13
+ spec/ghi/issue_spec.rb
14
+ spec/ghi_spec.rb
@@ -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
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
4
+ require "ghi/cli"
5
+ $stdout.sync = true
6
+ GHI::CLI::Executable.new.parse!(ARGV)
@@ -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
@@ -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