ghi 0.3.1 → 0.9.0.dev

Sign up to get free protection for your applications and to get access to all the features.
metadata CHANGED
@@ -1,70 +1,92 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: ghi
3
- version: !ruby/object:Gem::Version
4
- version: 0.3.1
5
- prerelease:
3
+ version: !ruby/object:Gem::Version
4
+ hash: -1101288818
5
+ prerelease: 6
6
+ segments:
7
+ - 0
8
+ - 9
9
+ - 0
10
+ - dev
11
+ version: 0.9.0.dev
6
12
  platform: ruby
7
- authors:
13
+ authors:
8
14
  - Stephen Celis
9
15
  autorequire:
10
16
  bindir: bin
11
17
  cert_chain: []
12
- date: 2012-01-13 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: rspec
16
- requirement: &70100746900540 !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - <
20
- - !ruby/object:Gem::Version
21
- version: '2.0'
22
- type: :development
23
- prerelease: false
24
- version_requirements: *70100746900540
25
- description: GitHub Issues on the command line. Use your `$EDITOR`, not your browser.
18
+
19
+ date: 2012-04-04 00:00:00 -07:00
20
+ default_executable:
21
+ dependencies: []
22
+
23
+ description: |
24
+ GitHub Issues on the command line. Use your `$EDITOR`, not your browser.
25
+
26
26
  email: stephen@stephencelis.com
27
- executables:
27
+ executables:
28
28
  - ghi
29
29
  extensions: []
30
- extra_rdoc_files:
31
- - README.rdoc
32
- files:
33
- - bin/ghi
34
- - lib/ghi/api.rb
35
- - lib/ghi/cli.rb
36
- - lib/ghi/issue.rb
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - lib/ghi/authorization.rb
35
+ - lib/ghi/client.rb
36
+ - lib/ghi/commands/assign.rb
37
+ - lib/ghi/commands/close.rb
38
+ - lib/ghi/commands/command.rb
39
+ - lib/ghi/commands/comment.rb
40
+ - lib/ghi/commands/config.rb
41
+ - lib/ghi/commands/edit.rb
42
+ - lib/ghi/commands/help.rb
43
+ - lib/ghi/commands/label.rb
44
+ - lib/ghi/commands/list.rb
45
+ - lib/ghi/commands/milestone.rb
46
+ - lib/ghi/commands/open.rb
47
+ - lib/ghi/commands/show.rb
48
+ - lib/ghi/commands/version.rb
49
+ - lib/ghi/commands.rb
50
+ - lib/ghi/formatting/colors.rb
51
+ - lib/ghi/formatting.rb
52
+ - lib/ghi/json.rb
37
53
  - lib/ghi.rb
38
- - spec/ghi/api_spec.rb
39
- - spec/ghi/cli_spec.rb
40
- - spec/ghi/issue_spec.rb
41
- - spec/ghi_spec.rb
42
- - README.rdoc
43
- homepage: http://github.com/stephencelis/ghi
54
+ - bin/ghi
55
+ has_rdoc: true
56
+ homepage: https://github.com/stephencelis/ghi
44
57
  licenses: []
58
+
45
59
  post_install_message:
46
- rdoc_options:
47
- - --main
48
- - README.rdoc
49
- require_paths:
60
+ rdoc_options: []
61
+
62
+ require_paths:
50
63
  - lib
51
- required_ruby_version: !ruby/object:Gem::Requirement
64
+ required_ruby_version: !ruby/object:Gem::Requirement
52
65
  none: false
53
- requirements:
54
- - - ! '>='
55
- - !ruby/object:Gem::Version
56
- version: '0'
57
- required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ hash: 3
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
74
  none: false
59
- requirements:
60
- - - ! '>='
61
- - !ruby/object:Gem::Version
62
- version: '0'
75
+ requirements:
76
+ - - ">"
77
+ - !ruby/object:Gem::Version
78
+ hash: 25
79
+ segments:
80
+ - 1
81
+ - 3
82
+ - 1
83
+ version: 1.3.1
63
84
  requirements: []
85
+
64
86
  rubyforge_project:
65
- rubygems_version: 1.8.11
87
+ rubygems_version: 1.6.2
66
88
  signing_key:
67
89
  specification_version: 3
68
90
  summary: GitHub Issues command line interface
69
91
  test_files: []
70
- has_rdoc: true
92
+
data/README.rdoc DELETED
@@ -1,126 +0,0 @@
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 ghi
14
-
15
-
16
- Go:
17
-
18
- Usage: ghi [options]
19
- -l, --list [state|term|number]
20
- --search, --show
21
- -v, --verbose
22
- --ssl
23
- -o, --open [title|number]
24
- --reopen
25
- -c, --closed, --close [number]
26
- -e, --edit [number]
27
- -r, --repo, --repository [name]
28
- -m, --comment [number|comment]
29
- -t, --label [number] [label]
30
- --claim [number]
31
- -d, --unlabel [number] [label]
32
- -u, --url [state|number]
33
- --[no-]color
34
- --[no-]pager
35
- -V, --version
36
- -h, --help
37
-
38
-
39
- == EXAMPLE?
40
-
41
- ghi works simply from within a repository. Some short examples:
42
-
43
- ghi -l # Lists all open issues
44
- ghi # Shorter shorthand for "ghi -l"
45
- ghi -v # Lists all open issues, verbosely (includes body)
46
- ghi -lc # Lists all closed issues
47
- ghi -l "doesn't work" # Searches for open issues matching "doesn't work"
48
- ghi -l invalid -c # Searches for closed issues matching "invalid"
49
- ghi -l1 # Shows issue 1
50
- ghi -1 # Shorter shorthand for "ghi -l1"
51
- ghi 1 # Shorter shorthand still
52
- ghi -o # Opens a new issue (in your $EDITOR)
53
- ghi -o "New issue" # Opens a new issue with the title "New issue"
54
- ghi -o "Title" -m "Body" # Opens a new issue with specified title and body
55
- ghi -e1 # Edits issue number 1 (in your $EDITOR)
56
- ghi -e1 -m "New body" # Edits issue number 1 with the specified body
57
- ghi -c1 # Closes issue 1
58
- ghi -c1 -m # Closes issue with comment (from your $EDITOR)
59
- ghi -c1 -m "Comment" # Closes issue with specified comment
60
- ghi -o1 # Reopens 1 (accepts comments, too)
61
- ghi -m1 # Comments on issue 1 (in your $EDITOR)
62
- ghi -t1 "tag" # Labels issue 1 with "tag"
63
- ghi -d1 "tag" # Removes the label, "tag"
64
- ghi --claim 1 # Tags issue 1 with your GitHub username
65
- ghi -u # Loads issues in your browser.
66
- ghi -u1 # Loads an issue in your browser.
67
-
68
-
69
- ghi also works anywhere:
70
-
71
- ghi -rghi # Your fork of "ghi"
72
- ghi -rstephencelis/ghi # Mine: "stephencelis/ghi"
73
- ghi stephencelis/ghi # Shorthand to merely list open.
74
-
75
-
76
- ghi uses ANSI colors if you use them in git.
77
-
78
- ghi looks for a <tt>$GHI_PAGER</tt> variable for paging.
79
-
80
- Always favor SSL by setting it:
81
-
82
- git config --global github.ssl true
83
-
84
-
85
- == CONTRIBUTORS
86
-
87
- * Jamie Macey (http://blog.tracefunc.com)
88
- * Hiroshi Nakamura (http://github.com/nahi)
89
- * David J. Hamilton
90
-
91
-
92
- === CONTRIBUTE?
93
-
94
- Running the tests should be as simple as a `bundle` and
95
- `bundle exec spec spec`.
96
-
97
- ghi is not under currently under the control of any gem packaging system. To
98
- build, use RubyGems:
99
-
100
- % gem build ghi.gemspec
101
- % sudo gem install ghi*.gem
102
-
103
-
104
- == LICENSE
105
-
106
- (The MIT License)
107
-
108
- (c) 2009-* Stephen Celis, stephen@stephencelis.com.
109
-
110
- Permission is hereby granted, free of charge, to any person obtaining a copy
111
- of this software and associated documentation files (the "Software"), to deal
112
- in the Software without restriction, including without limitation the rights
113
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
114
- copies of the Software, and to permit persons to whom the Software is
115
- furnished to do so, subject to the following conditions:
116
-
117
- The above copyright notice and this permission notice shall be included in all
118
- copies or substantial portions of the Software.
119
-
120
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
121
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
122
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
123
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
124
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
125
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
126
- SOFTWARE.
data/lib/ghi/api.rb DELETED
@@ -1,145 +0,0 @@
1
- require "net/https"
2
- require "yaml"
3
- require "cgi"
4
-
5
- class GHI::API
6
- class GHIError < StandardError
7
- end
8
-
9
- class InvalidRequest < GHIError
10
- end
11
-
12
- class InvalidConnection < GHIError
13
- end
14
-
15
- class ResponseError < GHIError
16
- end
17
-
18
- API_HOST = "github.com"
19
- API_PATH = "/api/v2/yaml/issues/:action/:user/:repo"
20
-
21
- attr_reader :user, :repo
22
-
23
- def initialize(user, repo, use_ssl = false)
24
- raise InvalidConnection if user.nil? || repo.nil?
25
- @user, @repo, @use_ssl = user, repo, use_ssl
26
- end
27
-
28
- def search(term, state = :open)
29
- get(:search, state, term)["issues"].map { |attrs| GHI::Issue.new(attrs) }
30
- end
31
-
32
- def list(state = :open)
33
- get(:list, state)["issues"].map { |attrs| GHI::Issue.new(attrs) }
34
- end
35
-
36
- def show(number)
37
- GHI::Issue.new get(:show, number)["issue"]
38
- end
39
-
40
- def comments(number)
41
- get(:comments, number)["comments"]
42
- end
43
-
44
- def open(title, body)
45
- if title.empty? && body.empty?
46
- raise GHIError, "Aborting request due to empty issue."
47
- end
48
- GHI::Issue.new post(:open, "title" => title, "body" => body)["issue"]
49
- end
50
-
51
- def edit(number, title, body)
52
- if title.empty? && body.empty?
53
- raise GHIError, "Aborting request due to empty issue."
54
- end
55
- res = post :edit, number, "title" => title, "body" => body
56
- GHI::Issue.new res["issue"]
57
- end
58
-
59
- def close(number)
60
- GHI::Issue.new post(:close, number)["issue"]
61
- end
62
-
63
- def reopen(number)
64
- GHI::Issue.new post(:reopen, number)["issue"]
65
- end
66
-
67
- def add_label(label, number)
68
- post("label/add", label, number)["labels"]
69
- end
70
-
71
- def remove_label(label, number)
72
- post("label/remove", label, number)["labels"]
73
- end
74
-
75
- def comment(number, comment)
76
- if comment.empty?
77
- raise GHIError, "Aborting request due to empty comment."
78
- end
79
- post(:comment, number, "comment" => comment)["comment"]
80
- end
81
-
82
- private
83
-
84
- def get(*args)
85
- res = nil
86
- http = Net::HTTP.new(API_HOST, @use_ssl ? 443 : 80)
87
- http.use_ssl = true if @use_ssl
88
- http.start do
89
- if @use_ssl
90
- req = Net::HTTP::Post.new path(*args)
91
- req.set_form_data auth
92
- else
93
- req = Net::HTTP::Get.new(path(*args) + auth(true))
94
- end
95
- res = YAML.load http.request(req).body
96
- end
97
-
98
- raise ResponseError, errors(res) if res["error"] || res[:error]
99
- res
100
- rescue ArgumentError, URI::InvalidURIError
101
- raise ResponseError, "GitHub hiccuped on your request"
102
- rescue SocketError
103
- raise ResponseError, "couldn't find the internet"
104
- end
105
-
106
- def post(*args)
107
- params = args.last.is_a?(Hash) ? args.pop : {}
108
-
109
- res = nil
110
- http = Net::HTTP.new(API_HOST, @use_ssl ? 443 : 80)
111
- http.use_ssl = true if @use_ssl
112
- http.start do
113
- req = Net::HTTP::Post.new path(*args)
114
- req.set_form_data params.merge(auth)
115
- res = YAML.load http.request(req).body
116
- end
117
-
118
- raise ResponseError, errors(res) if res["error"] || res[:error]
119
- res
120
- rescue ArgumentError, URI::InvalidURIError
121
- raise ResponseError, "GitHub hiccuped on your request"
122
- rescue SocketError
123
- raise ResponseError, "couldn't find the internet"
124
- end
125
-
126
- def errors(response)
127
- return response[:error] if response.key? :error
128
- [*response["error"]].map { |e| e["error"] } * ", "
129
- end
130
-
131
- def auth(query = false)
132
- if query
133
- "?login=#{GHI.login}&token=#{GHI.token}"
134
- else
135
- { "login" => GHI.login, "token" => GHI.token }
136
- end
137
- end
138
-
139
- def path(action, *args)
140
- @path ||= API_PATH.sub(":user", user).sub(":repo", repo)
141
- path = @path.sub ":action", action.to_s
142
- path << "/#{args.join("/")}" unless args.empty?
143
- path
144
- end
145
- end
data/lib/ghi/cli.rb DELETED
@@ -1,657 +0,0 @@
1
- require "optparse"
2
- require "tempfile"
3
- require "ghi"
4
- require "ghi/api"
5
- require "ghi/issue"
6
-
7
- begin
8
- require "launchy"
9
- rescue LoadError
10
- # No launchy!
11
- end
12
-
13
- module GHI::CLI #:nodoc:
14
- module FileHelper
15
- def launch_editor(file)
16
- system "#{editor} #{file.path}"
17
- end
18
-
19
- def gets_from_editor(issue)
20
- if windows?
21
- warn "Please supply the message with the -m option"
22
- exit 1
23
- end
24
-
25
- if in_repo?
26
- File.open message_path, "a+", &file_proc(issue)
27
- else
28
- Tempfile.open message_filename, &file_proc(issue)
29
- end
30
-
31
- return @message if comment?
32
- return @message.shift.strip, @message.join.sub(/\b\n\b/, " ").strip
33
- end
34
-
35
- def delete_message
36
- File.delete message_path
37
- rescue Errno::ENOENT, TypeError
38
- nil
39
- end
40
-
41
- def message_path
42
- File.join gitdir, message_filename
43
- end
44
-
45
- private
46
-
47
- def editor
48
- ENV["GHI_EDITOR"] || ENV["GIT_EDITOR"] ||
49
- `git config --get-all core.editor`.split.first || ENV["EDITOR"] || "vi"
50
- end
51
-
52
- def gitdir
53
- @gitdir ||= `git rev-parse --git-dir 2>/dev/null`.chomp
54
- end
55
-
56
- def message_filename
57
- @message_filename ||= "GHI_#{action.to_s.upcase}#{number}_MESSAGE"
58
- end
59
-
60
- def file_proc(issue)
61
- lambda do |file|
62
- file << edit_format(issue).join("\n") if File.zero? file.path
63
- file.rewind
64
- launch_editor file
65
- @message = File.readlines(file.path).find_all { |l| !l.match(/^#/) }
66
-
67
- if message.to_s =~ /\A\s*\Z/
68
- raise GHI::API::InvalidRequest, "can't file empty message"
69
- end
70
- raise GHI::API::InvalidRequest, "no change" if issue == message
71
- end
72
- end
73
-
74
- def in_repo?
75
- !gitdir.empty? && user == local_user && repo == local_repo
76
- end
77
- end
78
-
79
- module FormattingHelper
80
- def list_header(term = nil)
81
- if term
82
- "# #{state.to_s.capitalize} #{term.inspect} issues on #{user}/#{repo}"
83
- else
84
- "# #{state.to_s.capitalize} issues on #{user}/#{repo}"
85
- end
86
- end
87
-
88
- def list_format(issues, verbosity = nil)
89
- unless issues.empty?
90
- if verbosity
91
- issues.map { |i| ["=" * 79] + show_format(i) }
92
- else
93
- issues.map { |i| " #{i.number.to_s.rjust 3}: #{truncate(i.title, 72)} #{label_format(i.labels)}" }
94
- end
95
- else
96
- "none"
97
- end
98
- end
99
-
100
- def label_format(labels)
101
- labels and labels.map {|l| "[#{l}]"}.join(' ')
102
- end
103
-
104
- def edit_format(issue)
105
- l = []
106
- l << issue.title if issue.title && !comment?
107
- l << ""
108
- l << issue.body if issue.body && !comment?
109
- if comment?
110
- l << "# Please enter your comment."
111
- else
112
- l << "# Please explain the issue. The first line will become the title."
113
- end
114
- l << "# Lines beginning '#' will be ignored; ghi aborts empty messages."
115
- l << "# All line breaks will be honored in accordance with GFM:"
116
- l << "#"
117
- l << "# http://github.github.com/github-flavored-markdown"
118
- l << "#"
119
- l << "# On #{user}/#{repo}:"
120
- l << "#"
121
- l += show_format(issue, false).map { |line| "# #{line}" }
122
- end
123
-
124
- def show_format(issue, verbose = true)
125
- l = []
126
- l << " number: #{issue.number}" if issue.number
127
- l << " state: #{issue.state}" if issue.state
128
- l << " title: #{indent(issue.title, 15, 0).join}" if issue.title
129
- l << " labels: #{label_format(issue.labels)}" unless issue.labels.nil? || issue.labels.empty?
130
- l << " user: #{issue.user || GHI.login}"
131
- l << " votes: #{issue.votes}" if issue.votes
132
- l << " created at: #{issue.created_at}" if issue.created_at
133
- l << " updated at: #{issue.updated_at}" if issue.updated_at
134
- return l unless verbose
135
- l << ""
136
- l += indent(issue.body)[0..-2]
137
-
138
- comments = api.comments(issue.number)
139
- unless comments.empty?
140
- l << "=" * 79
141
- comments.each do |c|
142
- l << "#{c["user"]} commented:"
143
- l << ""
144
- l += indent(c["body"])
145
- l << "-" * 79
146
- end
147
- end
148
-
149
- l
150
- end
151
-
152
- def action_format(value = nil)
153
- key = "#{action.to_s.capitalize.sub(/e?$/, "ed")} issue #{number}"
154
- "#{key}: #{truncate(value.to_s, 78 - key.length)}"
155
- end
156
-
157
- def truncate(string, length)
158
- result = string.scan(/.{0,#{length - 3}}(?:\s|\Z)/).first.strip
159
- result << "..." if result != string
160
- result
161
- end
162
-
163
- def indent(string, level = 4, first = level)
164
- string = string.gsub(/\n{3,}/, "\n\n")
165
- lines = string.scan(/.{0,#{79 - level}}(?:\s|\Z)/).map { |line|
166
- " " * level + line
167
- }
168
- lines.first.sub!(/^\s+/) {} if first != level
169
- lines
170
- end
171
-
172
- private
173
-
174
- def comment?
175
- ![:open, :edit].include?(action)
176
- end
177
-
178
- def puts(*args)
179
- args = args.flatten.each { |arg|
180
- arg.gsub!(/\b\*(.+)\*\b/) { "\e[1m#$1\e[0m" } # Bold
181
- arg.gsub!(/\b_(.+)_\b/) { "\e[4m#$1\e[0m" } # Underline
182
- arg.gsub!(/(state:)?(# Open.*| open)$/) { "#$1\e[32m#$2\e[0m" }
183
- arg.gsub!(/(state:)?(# Closed.*| closed)$/) { "#$1\e[31m#$2\e[0m" }
184
- marked = [GHI.login, search_term, tag, "(?:#|gh)-\d+"].compact * "|"
185
- unless arg.include? "\e"
186
- arg.gsub!(/(#{marked})/i) { "\e[1;4;33m#{$&}\e[0m" }
187
- end
188
- } if colorize?
189
- rescue NoMethodError
190
- # Do nothing.
191
- ensure
192
- $stdout.puts(*args)
193
- end
194
-
195
- def colorize?
196
- return @colorize if defined? @colorize
197
- @colorize = if $stdout.isatty && !windows?
198
- !`git config --get-regexp color`.chomp.empty?
199
- else
200
- false
201
- end
202
- end
203
-
204
- def prepare_stdout
205
- return if @prepared || @no_pager || !$stdout.isatty || pager.nil?
206
- colorize? # Check for colorization.
207
- $stdout = pager
208
- @prepared = true
209
- end
210
-
211
- def pager
212
- return @pager if defined? @pager
213
- pager = ENV["GHI_PAGER"] || ENV["GIT_PAGER"] ||
214
- `git config --get-all core.pager`.split.first || ENV["PAGER"] ||
215
- "less -EMRX"
216
-
217
- @pager = IO.popen(pager, "w")
218
- end
219
-
220
- def windows?
221
- RUBY_PLATFORM.include? "mswin"
222
- end
223
- end
224
-
225
- class Executable
226
- include FileHelper, FormattingHelper
227
-
228
- attr_reader :message, :local_user, :local_repo, :user, :repo, :api,
229
- :action, :search_term, :number, :title, :body, :tag, :args, :verbosity,
230
- :use_ssl
231
-
232
- def parse!(*argv)
233
- @args, @argv = argv, argv.dup
234
-
235
- remotes = `git config --get-regexp remote\..+\.url`.split /\n/
236
- repo_expression = %r{([^:/]+)/([^/\s]+?)(?:\.git)?$}
237
- if remote = remotes.find { |r| r.include? "github.com" }
238
- remote.match repo_expression
239
- @user, @repo = $1, $2
240
- end
241
-
242
- option_parser.parse!(*args)
243
-
244
- if action.nil? && fallback_parsing(*args).nil?
245
- puts option_parser
246
- exit
247
- end
248
- rescue OptionParser::InvalidOption, OptionParser::InvalidArgument => e
249
- if fallback_parsing(*e.args).nil?
250
- warn "#{File.basename $0}: #{e.message}"
251
- puts option_parser
252
- exit 1
253
- end
254
- rescue OptionParser::MissingArgument, OptionParser::AmbiguousOption => e
255
- warn "#{File.basename $0}: #{e.message}"
256
- puts option_parser
257
- exit 1
258
- ensure
259
- run!
260
- $stdout.close_write
261
- end
262
-
263
- def run!
264
- @api = GHI::API.new user, repo, use_ssl
265
-
266
- case action
267
- when :search then search
268
- when :list then list
269
- when :show then show
270
- when :open then open
271
- when :edit then edit
272
- when :close then close
273
- when :reopen then reopen
274
- when :comment then prepare_comment && comment
275
- when :label, :claim then prepare_label && label
276
- when :unlabel then prepare_label && unlabel
277
- when :url then url
278
- end
279
- rescue GHI::API::InvalidConnection
280
- if action
281
- code = 1
282
- warn "#{File.basename $0}: not a GitHub repo"
283
- puts option_parser if args.flatten.empty?
284
- exit 1
285
- end
286
- rescue GHI::API::InvalidRequest => e
287
- warn "#{File.basename $0}: #{e.message} (#{user}/#{repo})"
288
- delete_message
289
- exit 1
290
- rescue GHI::API::ResponseError => e
291
- warn "#{File.basename $0}: #{e.message} (#{user}/#{repo})"
292
- exit 1
293
- rescue GHI::API::GHIError => e
294
- warn e.message
295
- exit 1
296
- end
297
-
298
- def commenting?
299
- @commenting
300
- end
301
-
302
- def state
303
- @state || :open
304
- end
305
-
306
- private
307
-
308
- def option_parser
309
- @option_parser ||= OptionParser.new { |opts|
310
- opts.banner = "Usage: #{File.basename $0} [options]"
311
-
312
- opts.on("-l", "--list", "--search", "--show [state|term|number]") do |v|
313
- @action = :list
314
- case v
315
- when nil, /^o(?:pen)?$/
316
- # Defaults.
317
- when /^\d+$/
318
- @action = :show
319
- @number = v.to_i
320
- when /^c(?:losed)?$/
321
- @state = :closed
322
- when /^[uw]$/
323
- @action = :url
324
- when /^v$/
325
- @verbosity = true
326
- else
327
- @action = :search
328
- @search_term = v
329
- end
330
- end
331
-
332
- opts.on("-v", "--verbose") do |v|
333
- if v
334
- @action ||= :list
335
- @verbosity = true
336
- end
337
- end
338
-
339
- opts.on("--ssl") do |ssl|
340
- @use_ssl = true
341
- end
342
-
343
- opts.on("-o", "--open", "--reopen [title|number]") do |v|
344
- @action = :open
345
- case v
346
- when /^\d+$/
347
- @action = :reopen
348
- @number = v.to_i
349
- when /^l$/
350
- @action = :list
351
- when /^m$/
352
- @title = args * " "
353
- when /^[uw]$/
354
- @action = :url
355
- else
356
- @title = v
357
- end
358
- end
359
-
360
- opts.on("-c", "--closed", "--close [number]") do |v|
361
- case v
362
- when /^\d+$/
363
- @action = :close
364
- @number = v.to_i unless v.nil?
365
- when /^l$/
366
- @action = :list
367
- @state = :closed
368
- when /^[uw]$/
369
- @action = :url
370
- @state = :closed
371
- when nil
372
- if @action.nil? || @number
373
- @action = :close
374
- else
375
- @state = :closed
376
- end
377
- else
378
- raise OptionParser::InvalidArgument
379
- end
380
- end
381
-
382
- opts.on("-e", "--edit [number]") do |v|
383
- case v
384
- when /^\d+$/
385
- @action = :edit
386
- @number = v.to_i
387
- when nil
388
- raise OptionParser::MissingArgument
389
- else
390
- raise OptionParser::InvalidArgument
391
- end
392
- end
393
-
394
- opts.on("-r", "--repo", "--repository [name]") do |v|
395
- case v
396
- when nil
397
- raise OptionParser::MissingArgument
398
- else
399
- repo = v.split "/"
400
- if repo.length == 1
401
- if @repo && `git remote 2>/dev/null`[/^#{repo}$/]
402
- repo << @repo
403
- else
404
- repo.unshift(GHI.login)
405
- end
406
- end
407
- @user, @repo = repo
408
- end
409
- end
410
-
411
- opts.on("-m", "--comment [number|comment]") do |v|
412
- case v
413
- when /^\d+$/, nil
414
- @action ||= :comment
415
- @number ||= v.to_i unless v.nil?
416
- @commenting = true
417
- else
418
- @body = v
419
- end
420
- end
421
-
422
- opts.on("-t", "--label [number] [label]") do |v|
423
- raise OptionParser::MissingArgument if v.nil?
424
- @action ||= :label
425
- @number = v.to_i
426
- end
427
-
428
- opts.on("--claim [number]") do |v|
429
- raise OptionParser::MissingArgument if v.nil?
430
- @action = :claim
431
- @number = v.to_i
432
- @tag = GHI.login
433
- end
434
-
435
- opts.on("-d", "--unlabel [number] [label]") do |v|
436
- @action = :unlabel
437
- case v
438
- when /^\d+$/
439
- @number = v.to_i
440
- when /^\w+$/
441
- @tag = v
442
- end
443
- end
444
-
445
- opts.on("-u", "-w", "--url", "--web [state|number]") do |v|
446
- @action = :url
447
- case v
448
- when /^\d+$/
449
- @number = v.to_i
450
- when /^c(?:losed)?$/
451
- @state = :closed
452
- when /^u(?:nread)?$/
453
- @state = :unread
454
- end
455
- end
456
-
457
- opts.on("--[no-]color") do |v|
458
- @colorize = v
459
- end
460
-
461
- opts.on("--[no-]pager") do |v|
462
- @no_pager = (v == false)
463
- end
464
-
465
- opts.on_tail("-V", "--version") do
466
- puts "#{File.basename($0)}: v#{GHI::VERSION}"
467
- exit
468
- end
469
-
470
- opts.on_tail("-h", "--help") do
471
- puts opts
472
- exit
473
- end
474
- }
475
- end
476
-
477
- def search
478
- prepare_stdout
479
- puts list_header(search_term)
480
- issues = api.search search_term, state
481
- puts list_format(issues, verbosity)
482
- end
483
-
484
- def list
485
- prepare_stdout
486
- puts list_header
487
- issues = api.list(state)
488
- puts list_format(issues, verbosity)
489
- end
490
-
491
- def show
492
- prepare_stdout
493
- issue = api.show number
494
- puts show_format(issue)
495
- end
496
-
497
- def open
498
- if title.nil?
499
- new_title, new_body = gets_from_editor GHI::Issue.new("title" => body)
500
- elsif @commenting && body.nil?
501
- new_title, new_body = gets_from_editor GHI::Issue.new("title" => title)
502
- end
503
- new_title ||= title
504
- new_body ||= body
505
- issue = api.open new_title, new_body
506
- delete_message
507
- @number = issue.number
508
- puts action_format(issue.title)
509
- end
510
-
511
- def edit
512
- shown = api.show number
513
- new_title, new_body = gets_from_editor(shown) if body.nil?
514
- new_title ||= shown.title
515
- new_body ||= body
516
- issue = api.edit number, new_title, new_body
517
- delete_message
518
- puts action_format(issue.title)
519
- end
520
-
521
- def close
522
- raise GHI::API::InvalidRequest, "need a number" if number.nil?
523
- issue = api.close number
524
- if @commenting || new_body = body
525
- new_body ||= gets_from_editor issue
526
- comment = api.comment number, new_body
527
- end
528
- puts action_format(issue.title)
529
- puts "(commented)" if comment
530
- end
531
-
532
- def reopen
533
- issue = api.reopen number
534
- if @commenting || new_body = body
535
- new_body ||= gets_from_editor issue
536
- comment = api.comment number, new_body
537
- end
538
- puts action_format(issue.title)
539
- puts "(commented)" if comment
540
- end
541
-
542
- def prepare_label
543
- @tag ||= (body || args * " ")
544
- raise GHI::API::InvalidRequest, "need a label" if @tag.empty?
545
- true
546
- end
547
-
548
- def label
549
- labels = api.add_label tag, number
550
- puts action_format
551
- puts indent(labels.join(", "))
552
- end
553
-
554
- def unlabel
555
- labels = api.remove_label tag, number
556
- puts action_format
557
- puts indent(labels.empty? ? "no labels" : labels.join(", "))
558
- end
559
-
560
- def prepare_comment
561
- @body = args.flatten.first
562
- @commenting = false unless body.nil?
563
- true
564
- end
565
-
566
- def comment
567
- @body ||= gets_from_editor api.show(number)
568
- comment = api.comment(number, body)
569
- delete_message
570
- puts "(comment})"
571
- end
572
-
573
- def url
574
- url = "https://github.com/#{user}/#{repo}/issues"
575
- if number.nil?
576
- url << "/#{state}" unless state == :open
577
- else
578
- url << "/#{number}"
579
- end
580
- defined?(Launchy) ? Launchy.open(url) : puts(url)
581
- end
582
-
583
- #-
584
- # Because these are mere fallbacks, any options used earlier will muddle
585
- # things: `ghi list` will work, `ghi list -c` will not.
586
- #
587
- # Argument parsing will have to better integrate with option parsing to
588
- # overcome this.
589
- #+
590
- def fallback_parsing(*arguments)
591
- arguments = arguments.flatten
592
- case command = arguments.shift
593
- when nil, "list"
594
- @action = :list
595
- if arg = arguments.shift
596
- @state ||= arg.to_sym if %w(open closed).include? arg
597
- @user, @repo = arg.split "/" if arg.count("/") == 1
598
- end
599
- when "search"
600
- @action = :search
601
- @search_term ||= arguments.shift
602
- when "show", /^-?(\d+)$/
603
- @action = :show
604
- @number ||= ($1 || arguments.shift[/\d+/]).to_i
605
- when "open"
606
- if arguments.first =~ /^\d+$/
607
- @action = :reopen
608
- @number ||= arguments.shift[/\d+/].to_i
609
- else
610
- @action = :open
611
- @title = arguments.join(' ')
612
- end
613
- when "edit"
614
- @action = :edit
615
- @number ||= arguments.shift[/\d+/].to_i
616
- when "close"
617
- @action = :close
618
- @number ||= arguments.shift[/\d+/].to_i
619
- when "reopen"
620
- @action = :reopen
621
- @number ||= arguments.shift[/\d+/].to_i
622
- when "label"
623
- @action = :label
624
- @number ||= arguments.shift[/\d+/].to_i
625
- @label ||= arguments.shift
626
- when "unlabel"
627
- @action = :unlabel
628
- @number ||= arguments.shift[/\d+/].to_i
629
- @label ||= arguments.shift
630
- when "comment"
631
- @action = :comment
632
- @number ||= arguments.shift[/\d+/].to_i
633
- when "claim"
634
- @action = :claim
635
- @number ||= arguments.shift[/\d+/].to_i
636
- when %r{^([^/]+)/([^/]+)$}
637
- @action = :list
638
- @user, @repo = $1, $2
639
- when "url", "web"
640
- @action = :url
641
- @number ||= arguments.shift[/\d+/].to_i
642
- end
643
-
644
- @use_ssl ||= `git config github.ssl`.chomp == 'true'
645
-
646
- if @action
647
- @args = @argv.dup
648
- args.delete_if { |arg| arg == command }
649
- option_parser.parse!(*args)
650
- return true
651
- end
652
- unless command.start_with? "-"
653
- warn "#{File.basename $0}: what do you mean, '#{command}'?"
654
- end
655
- end
656
- end
657
- end