Class: GitIssue::Base

Inherits:
Object
  • Object
show all
Includes:
Helper, Term::ANSIColor
Defined in:
lib/git_issue/base.rb

Direct Known Subclasses

Github, Redmine

Constant Summary collapse

BRANCH_NAME_FORMAT =
"ticket/id/%s"

Constants included from Helper

Helper::CONFIGURE_MESSAGE

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Helper

configure_error, configured_value, get_body_from_editor, get_title_and_body_from_editor, #git_dir, #git_editor, global_configured_value, its_klass_of, #open_editor, #read_body, #split_head_and_body

Constructor Details

#initialize(args, options = {}) ⇒ Base

Returns a new instance of Base.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/git_issue/base.rb', line 10

def initialize(args, options = {})

  @opt_parse_obj = opt_parser
  args = parse_options(args)

  @sysout = options[:sysout] || $stdout
  @syserr = options[:syserr] || $stderr

  split_ticket = lambda{|s| s.nil? || s.empty? ? nil : s.split(/,/).map{|v| v.strip.to_i} }

  @tickets = []
  cmd = args.shift

  if cmd =~ /(\d+,?\s?)+/
    @tickets = split_ticket.call(cmd)
    cmd = nil
  end

  @tickets += args.map{|s| split_ticket.call(s)}.flatten.uniq
  @tickets = [guess_ticket].compact if @tickets.empty?

  cmd ||= (@tickets.nil? || @tickets.empty?) ? default_cmd : :show
  cmd = cmd.to_sym

  @command = find_command(cmd)

  exit_with_message("invalid command <#{cmd}>") unless @command
end

Instance Attribute Details

#apikeyObject (readonly)

Returns the value of attribute apikey.



7
8
9
# File 'lib/git_issue/base.rb', line 7

def apikey
  @apikey
end

#commandObject (readonly)

Returns the value of attribute command.



7
8
9
# File 'lib/git_issue/base.rb', line 7

def command
  @command
end

#optionsObject (readonly)

Returns the value of attribute options.



7
8
9
# File 'lib/git_issue/base.rb', line 7

def options
  @options
end

#syserrObject

Returns the value of attribute syserr.



8
9
10
# File 'lib/git_issue/base.rb', line 8

def syserr
  @syserr
end

#sysoutObject

Returns the value of attribute sysout.



8
9
10
# File 'lib/git_issue/base.rb', line 8

def sysout
  @sysout
end

#ticketsObject (readonly)

Returns the value of attribute tickets.



7
8
9
# File 'lib/git_issue/base.rb', line 7

def tickets
  @tickets
end

Instance Method Details

#apply_colors(str, *colors) ⇒ Object



302
303
304
# File 'lib/git_issue/base.rb', line 302

def apply_colors(str, *colors)
  @no_color.present? ? str : (colors.map(&method(:send)) + [str, reset]).join
end

#cherry(option = {}) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/git_issue/base.rb', line 80

def cherry(option = {})
  upstream = options[:upstream]
  head = options[:head]

  commits = %x(git cherry -v #{upstream} #{head}).split(/\n/).map{|s|
    s.scan(/^([+-])\s(\w+)\s(.*)/).first
  }.select{|_, _, msg| msg =~ /#[0-9]+/ }.map{|diff, sha1, msg|
    msg.scan(/#([0-9]+)/).flatten.map{|ticket| [diff, sha1, msg, ticket]}
  }.flatten(1)

  commits.group_by{|d, _, _, n| [d, n]}.each do |k, records|
    diff, ticket = k
    c = case diff
        when "-" then :red
        when "+" then :green
    end

    issue = fetch_issue(ticket, options)

    puts "#{apply_colors(diff, c)} #{oneline_issue(issue, options)}"
    if options[:verbose]
      records.each {|_, sha1, msg| puts "  #{sha1} #{msg}" }
      puts ""
    end
  end
end

#commandsObject



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/git_issue/base.rb', line 107

def commands
  [
  GitIssue::Command.new(:show,   :s, 'show given issue summary. if given no id,  geuss id from current branch name.'),
  GitIssue::Command.new(:list,   :l, 'listing issues.'),
  GitIssue::Command.new(:mine,   :m, 'display issues that assigned to you.'),
  GitIssue::Command.new(:commit, :c, 'commit with filling issue subject to messsage.if given no id, geuss id from current branch name.'),
  GitIssue::Command.new(:add,    :a, 'create issue.'),
  GitIssue::Command.new(:update, :u, 'update issue properties. if given no id, geuss id from current branch name.'),
  GitIssue::Command.new(:branch, :b, "checout to branch using specified issue id. if branch dose'nt exisits, create it. (ex ticket/id/<issue_id>)"),
  GitIssue::Command.new(:cherry, :chr, 'find issue not merged upstream.'),

  GitIssue::Command.new(:publish,:pub, "push branch to remote repository and set upstream "),
  GitIssue::Command.new(:rebase, :rb,  "rebase branch onto specific newbase"),

  GitIssue::Command.new(:help,   :h, "show usage.")
  ]
end

#connection(host, port) ⇒ Object



306
307
308
309
310
311
312
313
314
315
# File 'lib/git_issue/base.rb', line 306

def connection(host, port)
  env = ENV['http_proxy'] || ENV['HTTP_PROXY']
  if env
    uri = URI(env)
    proxy_host, proxy_port = uri.host, uri.port
    Net::HTTP::Proxy(proxy_host, proxy_port).new(host, port)
  else
    Net::HTTP.new(host, port)
  end
end

#current_branchObject



162
163
164
165
166
# File 'lib/git_issue/base.rb', line 162

def current_branch
  RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|bccwin|cygwin/ ?
    %x(git branch -l 2> NUL | grep "*" | cut -d " " -f 2).strip :
    %x(git branch -l 2> /dev/null | grep "*" | cut -d " " -f 2).strip
end

#default_cmdObject



39
40
41
# File 'lib/git_issue/base.rb', line 39

def default_cmd
  :list
end

#err(msg) ⇒ Object



298
299
300
# File 'lib/git_issue/base.rb', line 298

def err(msg)
  @syserr.puts msg
end

#executeObject



43
44
45
46
47
48
49
50
51
52
# File 'lib/git_issue/base.rb', line 43

def execute
  if @tickets.nil? ||  @tickets.empty?
    self.send(@command.name, @options)
  else
    @tickets.each do |ticket|
      self.send(@command.name, @options.merge(:ticket_id => ticket))
    end
  end
  true
end

#exit_with_message(msg, status = 1) ⇒ Object



151
152
153
154
# File 'lib/git_issue/base.rb', line 151

def exit_with_message(msg, status=1)
  err msg
  exit(status)
end

#find_command(cmd) ⇒ Object



125
126
127
128
# File 'lib/git_issue/base.rb', line 125

def find_command(cmd)
  cmd = cmd.to_sym
  commands.find{|c| c.name == cmd || c.short_name == cmd }
end

#guess_ticketObject



168
169
170
171
172
173
# File 'lib/git_issue/base.rb', line 168

def guess_ticket
  branch = current_branch
  if branch =~ %r!id/(\d+)! || branch =~ /^(\d+)_/ || branch =~ /_(\d+)$/
    ticket = $1
  end
end

#help(options = {}) ⇒ Object



54
55
56
57
58
59
60
61
# File 'lib/git_issue/base.rb', line 54

def help(options = {})
  puts @opt_parse_obj.banner
  puts "  Commnads:"
  puts usage
  puts ""
  puts "  Options:"
  puts @opt_parse_obj.summarize
end

#mktmpdir(prefix_suffix = nil, tmpdir = nil) ⇒ Object

for 1.8.6…



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/git_issue/base.rb', line 224

def mktmpdir(prefix_suffix=nil, tmpdir=nil)
  case prefix_suffix
  when nil
    prefix = "d"
    suffix = ""
  when String
    prefix = prefix_suffix
    suffix = ""
  when Array
    prefix = prefix_suffix[0]
    suffix = prefix_suffix[1]
  else
    raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
  end
  tmpdir ||= Dir.tmpdir
  t = Time.now.strftime("%Y%m%d")
  n = nil
  begin
    path = "#{tmpdir}/#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
    path << "-#{n}" if n
    path << suffix
    Dir.mkdir(path, 0700)
  rescue Errno::EEXIST
    n ||= 0
    n += 1
    retry
  end

  if block_given?
    begin
      yield path
    ensure
      FileUtils.remove_entry_secure path
    end
  else
    path
  end
end

#mlength(s) ⇒ Object

this is unnecessary hacks for multibytes charactors handling…



197
198
199
200
201
202
# File 'lib/git_issue/base.rb', line 197

def mlength(s)
  width = 0
  cnt = 0
  s.split(//u).each{|c| cnt += 1 ;width += 1 if c.length > 1 }
  cnt + width
end

#mljust(s, n) ⇒ Object

this is unnecessary hacks for multibytes charactors handling…



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/git_issue/base.rb', line 205

def mljust(s, n)
  return "" unless s
  cnt = 0
  chars = []

  s.split(//u).each do |c|
    next if cnt > n
    chars << c
    cnt += c =~ /^[^ -~。-゚]*$/ ? 2 : 1
  end
  if cnt > n
    chars.pop
    cnt -= chars.last =~ /^[^ -~。-゚]*$/ ? 2 : 1
  end
  chars << " " * (n - cnt) if n > cnt
  chars.join
end

#opt_parserObject



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/git_issue/base.rb', line 273

def opt_parser
  OptionParser.new{|opts|
    opts.banner = 'git issue <command> [ticket_id] [<args>]'
    opts.on("--all",        "-a", "update all paths in the index file "){ @options[:all] = true }
    opts.on("--force",      "-f", "force create branch"){ @options[:force] = true }
    opts.on("--verbose",    "-v", "show issue details"){|v| @options[:verbose] = true}
    opts.on("--max-count=VALUE", "-n=VALUE", "maximum number of issues "){|v| @options[:max_count] = v.to_i}
    opts.on("--oneline",          "display short info"){|v| @options[:oneline] = true}
    opts.on("--raw-id",           "output ticket number only"){|v| @options[:raw_id] = true}
    opts.on("--remote=VALUE",     'on publish, remote repository to push branch ') {|v| @options[:remote] = v}
    opts.on("--onto=VALUE",       'on rebase, start new branch with HEAD equal to "newbase" ') {|v| @options[:onto] = v}

    opts.on("--upstream=VALUE",   'on cherry, upstream branch to compare against. default is tracked remote branch') {|v| @options[:upstream] = v}
    opts.on("--head=VALUE",       'on cherry, working branch. defaults to HEAD') {|v| @options[:head] = v}

    opts.on("--no-color", "turn off colored output"){@no_color = true }
    opts.on("--debug", "debug print"){@debug= true }
  }

end

#parse_options(args) ⇒ Object



267
268
269
270
271
# File 'lib/git_issue/base.rb', line 267

def parse_options(args)
  @options = {}
  @opt_parse_obj.parse!(args)
  args
end

#prompt(name) ⇒ Object



191
192
193
194
# File 'lib/git_issue/base.rb', line 191

def prompt(name)
 print "#{name}: "
 $stdin.gets.chop
end

#publish(options = {}) ⇒ Object



63
64
65
66
67
# File 'lib/git_issue/base.rb', line 63

def publish(options = {})
  ticket, branch_name = ticket_and_branch(options)
  remote = options[:remote] || "origin"
  system "git push -u #{remote} #{branch_name}"
end

#puts(msg) ⇒ Object



294
295
296
# File 'lib/git_issue/base.rb', line 294

def puts(msg)
  @sysout.puts msg
end

#rebase(options = {}) ⇒ Object



69
70
71
72
73
74
75
76
77
78
# File 'lib/git_issue/base.rb', line 69

def rebase(options = {})
  raise '--onto is required.' unless options[:onto]
  ticket, branch_name = ticket_and_branch(options)
  onto = options[:onto]

  cb = current_branch

  system "git rebase --onto #{onto} #{onto} #{branch_name}"
  system "git checkout #{cb}"
end

#response_success?(response) ⇒ Boolean

Returns:

  • (Boolean)


186
187
188
189
# File 'lib/git_issue/base.rb', line 186

def response_success?(response)
  code = response.code.to_i
  code >= 200 && code < 300
end

#ticket_and_branch(options) ⇒ Object



175
176
177
178
179
180
181
182
183
184
# File 'lib/git_issue/base.rb', line 175

def ticket_and_branch(options)
  if options[:ticket_id]
    ticket = options[:ticket_id]
    branch_name = ticket_branch(ticket)
  else
    branch_name = current_branch
    ticket = guess_ticket
  end
  [ticket, branch_name]
end

#ticket_branch(ticket_id) ⇒ Object



158
159
160
# File 'lib/git_issue/base.rb', line 158

def ticket_branch(ticket_id)
  BRANCH_NAME_FORMAT % ticket_id
end

#time_ago_in_words(time) ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/git_issue/base.rb', line 134

def time_ago_in_words(time)
  t = Time.parse(time)
  a = (Time.now - t).to_i

  case a
    when 0              then return 'just now'
    when 1..59          then return a.to_s + '秒前'
    when 60..119        then return '1分前'
    when 120..3540      then return (a/60).to_i.to_s + '分前'
    when 3541..7100     then return '1時間前'
    when 7101..82800    then return ((a+99)/3600).to_i.to_s + '時間前'
    when 82801..172000  then return '1日前'
    when 172001..432000 then return ((a+800)/(60*60*24)).to_i.to_s + '日前'
    else return ((a+800)/(60*60*24)).to_i.to_s + '日前'
  end
end

#to_date(d) ⇒ Object



263
264
265
# File 'lib/git_issue/base.rb', line 263

def to_date(d)
  Date.parse(d).strftime('%Y/%m/%d') rescue d
end

#usageObject



130
131
132
# File 'lib/git_issue/base.rb', line 130

def usage
  commands.map{|c| "%-8s %s %s" % [c.name, c.short_name, c.description ] }.join("\n")
end