Class: GitIssue::Base

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

Direct Known Subclasses

Bitbucket, 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_editor, global_configured_value, its_klass_of, #open_editor, #read_body, #split_head_and_body, #work_dir

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



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

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
124
# 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(:view,   :v, 'view issue in browser. 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



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

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

#current_branchObject



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

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



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

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



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

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

#find_command(cmd) ⇒ Object



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

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

#guess_ticketObject



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

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…



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
262
# File 'lib/git_issue/base.rb', line 225

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…



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

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…



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

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



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

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



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

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

#prompt(name) ⇒ Object



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

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



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

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)


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

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

#ticket_and_branch(options) ⇒ Object



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

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



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

def ticket_branch(ticket_id)
  BRANCH_NAME_FORMAT % ticket_id
end

#time_ago_in_words(time) ⇒ Object



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

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



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

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

#usageObject



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

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