2014-02-21 18:10:06 +04:00
#!/usr/bin/env ruby
require 'open-uri'
2014-02-22 15:29:21 +04:00
require 'openssl'
2014-02-21 18:10:06 +04:00
require 'net/http'
require 'json'
require 'io/console'
require 'stringio'
require 'strscan'
2014-02-22 15:29:21 +04:00
require 'optparse'
2015-03-03 18:30:54 +03:00
require 'abbrev'
2014-02-21 18:10:06 +04:00
require 'pp'
2019-04-28 13:33:41 +03:00
require 'shellwords'
2015-01-20 07:09:24 +03:00
begin
require 'readline'
rescue LoadError
2015-01-20 07:23:43 +03:00
module Readline ; end
2015-01-20 07:09:24 +03:00
end
2014-02-21 18:10:06 +04:00
2014-02-22 15:29:21 +04:00
VERSION = '0.0.1'
opts = OptionParser . new
target_version = nil
repo_path = nil
api_key = nil
ssl_verify = true
opts . on ( '-k REDMINE_API_KEY' , '--key=REDMINE_API_KEY' , 'specify your REDMINE_API_KEY' ) { | v | api_key = v }
opts . on ( '-t TARGET_VERSION' , '--target=TARGET_VARSION' , / \ A \ d(?: \ . \ d)+ \ z / , 'specify target version (ex: 2.1)' ) { | v | target_version = v }
opts . on ( '-r RUBY_REPO_PATH' , '--repository=RUBY_REPO_PATH' , 'specify repository path' ) { | v | repo_path = v }
opts . on ( '--[no-]ssl-verify' , TrueClass , 'use / not use SSL verify' ) { | v | ssl_verify = v }
opts . version = VERSION
opts . parse! ( ARGV )
http_options = { use_ssl : true }
http_options [ :verify_mode ] = OpenSSL :: SSL :: VERIFY_NONE unless ssl_verify
2015-03-03 20:14:22 +03:00
$openuri_options = { }
$openuri_options [ :ssl_verify_mode ] = OpenSSL :: SSL :: VERIFY_NONE unless ssl_verify
2014-02-22 15:29:21 +04:00
TARGET_VERSION = target_version || ENV [ 'TARGET_VERSION' ] || ( raise 'need to specify TARGET_VERSION' )
RUBY_REPO_PATH = repo_path || ENV [ 'RUBY_REPO_PATH' ]
2014-02-21 18:10:06 +04:00
BACKPORT_CF_KEY = 'cf_5'
STATUS_CLOSE = 5
2014-02-22 15:29:21 +04:00
REDMINE_API_KEY = api_key || ENV [ 'REDMINE_API_KEY' ] || ( raise 'need to specify REDMINE_API_KEY' )
2014-02-21 18:10:06 +04:00
REDMINE_BASE = 'https://bugs.ruby-lang.org'
@query = {
'f[]' = > BACKPORT_CF_KEY ,
" op[ #{ BACKPORT_CF_KEY } ] " = > '~' ,
2023-01-18 11:57:03 +03:00
" v[ #{ BACKPORT_CF_KEY } ][] " = > " \" #{ TARGET_VERSION } : REQUIRED \" " ,
2014-02-21 18:10:06 +04:00
'limit' = > 40 ,
'status_id' = > STATUS_CLOSE ,
'sort' = > 'updated_on'
}
PRIORITIES = {
'Low' = > [ :white , :blue ] ,
'Normal' = > [ ] ,
'High' = > [ :red ] ,
'Urgent' = > [ :red , :white ] ,
'Immediate' = > [ :red , :white , { underscore : true } ] ,
}
COLORS = {
black : 30 ,
red : 31 ,
green : 32 ,
yellow : 33 ,
blue : 34 ,
magenta : 35 ,
cyan : 36 ,
white : 37 ,
}
class String
def color ( fore = nil , back = nil , bold : false , underscore : false )
seq = " "
if bold
seq << " \e [1m "
end
if underscore
seq << " \e [2m "
end
if fore
c = COLORS [ fore ]
raise " unknown foreground color #{ fore } " unless c
seq << " \e [ #{ c } m "
end
if back
2014-02-22 15:50:56 +04:00
c = COLORS [ back ]
2014-02-21 18:10:06 +04:00
raise " unknown background color #{ back } " unless c
2014-02-22 15:50:56 +04:00
seq << " \e [ #{ c + 10 } m "
2014-02-21 18:10:06 +04:00
end
if seq . empty?
self
else
seq << self << " \e [0m "
end
end
end
class StringScanner
2019-12-20 03:19:39 +03:00
# lx: limit of x (columns of screen)
2014-02-21 18:10:06 +04:00
# ly: limit of y (rows of screen)
def getrows ( lx , ly )
cp1 = charpos
x = 0
y = 0
until eos?
case c = getch
when " \r "
x = 0
when " \n "
x = 0
y += 1
when " \t "
x += 8
when / [ \ x00- \ x7f] /
# halfwidth
x += 1
else
# fullwidth
x += 2
end
if x > lx
x = 0
y += 1
unscan
end
if y > = ly
return string [ cp1 ... charpos ]
end
end
string [ cp1 .. - 1 ]
end
end
def more ( sio )
console = IO . console
ly , lx = console . winsize
ly -= 1
str = sio . string
cls = " \r " + ( " " * lx ) + " \r "
ss = StringScanner . new ( str )
rows = ss . getrows ( lx , ly )
puts rows
until ss . eos?
print " : "
case c = console . getch
2014-02-27 08:10:00 +04:00
when ' '
2014-02-21 18:10:06 +04:00
rows = ss . getrows ( lx , ly )
puts cls + rows
2014-02-27 08:10:00 +04:00
when 'j' , " \r "
2014-02-21 18:10:06 +04:00
rows = ss . getrows ( lx , 1 )
puts cls + rows
when " q "
print cls
break
else
print " \b "
end
end
end
2015-01-27 10:00:50 +03:00
class << Readline
def readline ( prompt = '' )
console = IO . console
console . binmode
2018-05-18 03:38:00 +03:00
_ , lx = console . winsize
2015-01-27 10:00:50 +03:00
if / mswin|mingw / =~ RUBY_PLATFORM or / ^(?:vt \ d \ d \ d|xterm) /i =~ ENV [ " TERM " ]
cls = " \r \e [2K "
else
cls = " \r " << ( " " * lx )
end
cls << " \r " << prompt
console . print prompt
console . flush
line = ''
2018-05-18 03:37:59 +03:00
while true
2015-01-27 10:00:50 +03:00
case c = console . getch
when " \r " , " \n "
puts
HISTORY << line
return line
when " \ C-? " , " \b " # DEL/BS
print " \b \b " if line . chop!
when " \ C-u "
print cls
line . clear
when " \ C-d "
return nil if line . empty?
line << c
when " \ C-p "
HISTORY . pos -= 1
line = HISTORY . current
print cls
print line
when " \ C-n "
HISTORY . pos += 1
line = HISTORY . current
print cls
print line
else
2015-03-03 17:42:15 +03:00
if c > = " "
print c
line << c
end
2015-01-27 10:00:50 +03:00
end
end
2015-01-20 07:09:13 +03:00
end
2015-01-27 10:00:50 +03:00
HISTORY = [ ]
def HISTORY . << ( val )
HISTORY . push ( val )
@pos = self . size
self
end
def HISTORY . pos
@pos || = 0
end
def HISTORY . pos = ( val )
@pos = val
if @pos < 0
@pos = - 1
elsif @pos > = self . size
@pos = self . size
end
end
def HISTORY . current
@pos || = 0
if @pos < 0 || @pos > = self . size
''
2015-01-20 05:25:48 +03:00
else
2015-01-27 10:00:50 +03:00
self [ @pos ]
2015-01-20 05:25:48 +03:00
end
end
2015-01-20 07:09:24 +03:00
end unless defined? ( Readline . readline )
2015-01-20 05:25:48 +03:00
2014-02-22 17:43:16 +04:00
def find_svn_log ( pattern )
2015-01-22 12:05:53 +03:00
` svn log --xml --stop-on-copy --search=" #{ pattern } " #{ RUBY_REPO_PATH } `
2014-02-22 17:43:16 +04:00
end
2019-04-28 13:33:41 +03:00
def find_git_log ( pattern )
2020-03-13 16:27:54 +03:00
` git #{ RUBY_REPO_PATH ? " -C #{ RUBY_REPO_PATH . shellescape } " : " " } log --grep=" #{ pattern } " `
2019-04-28 13:33:41 +03:00
end
2021-02-02 13:14:37 +03:00
def has_commit ( commit , branch )
base = RUBY_REPO_PATH ? [ " -C " , RUBY_REPO_PATH . shellescape ] : nil
system ( " git " , * base , " merge-base " , " --is-ancestor " , commit , branch )
end
2014-02-21 18:10:06 +04:00
def show_last_journal ( http , uri )
res = http . get ( " #{ uri . path } ?include=journals " )
res . value
h = JSON ( res . body )
x = h [ " issue " ]
raise " no issue " unless x
x = x [ " journals " ]
raise " no journals " unless x
x = x . last
puts " == #{ x [ " user " ] [ " name " ] } ( #{ x [ " created_on " ] } ) "
x [ " details " ] . each do | y |
puts JSON ( y )
end
puts x [ " notes " ]
end
2016-03-29 12:59:27 +03:00
def merger_path
2016-04-22 09:07:19 +03:00
RUBY_PLATFORM =~ / mswin|mingw / ? 'merger' : File . expand_path ( '../merger.rb' , __FILE__ )
2016-03-29 12:59:27 +03:00
end
2014-02-21 18:10:06 +04:00
def backport_command_string
2015-03-03 20:14:22 +03:00
unless @changesets . respond_to? ( :validated )
@changesets = @changesets . select do | c |
2019-04-21 17:24:38 +03:00
next false if c . match ( / \ A \ d{1,6} \ z / ) # skip SVN revision
2021-02-02 13:14:37 +03:00
# check if the Git revision is included in master
has_commit ( c , " master " )
2015-03-03 20:14:22 +03:00
end
@changesets . define_singleton_method ( :validated ) { true }
end
2016-04-15 19:34:22 +03:00
" #{ merger_path } --ticket= #{ @issue } #{ @changesets . sort . join ( ',' ) } "
2014-02-21 18:10:06 +04:00
end
2015-02-23 12:30:24 +03:00
def status_char ( obj )
case obj [ " name " ]
when " Closed "
" C " . color ( bold : true )
else
obj [ " name " ] [ 0 ]
end
end
2014-02-21 18:10:06 +04:00
console = IO . console
2018-05-18 03:38:00 +03:00
row , = console . winsize
2014-02-21 18:10:06 +04:00
@query [ 'limit' ] = row - 2
puts " Backporter #{ VERSION } " . color ( bold : true ) + " for #{ TARGET_VERSION } "
2015-03-03 18:30:54 +03:00
class CommandSyntaxError < RuntimeError ; end
commands = {
" ls " = > proc { | args |
raise CommandSyntaxError unless / \ A( \ d+)? \ z / =~ args
2020-01-01 09:06:18 +03:00
uri = URI ( REDMINE_BASE + '/projects/ruby-master/issues.json?' + URI . encode_www_form ( @query . dup . merge ( 'page' = > ( $1 ? $1 . to_i : 1 ) ) ) )
2014-02-21 18:10:06 +04:00
# puts uri
2015-03-03 20:14:22 +03:00
res = JSON ( uri . read ( $openuri_options ) )
2014-02-21 18:10:06 +04:00
@issues = issues = res [ " issues " ]
from = res [ " offset " ] + 1
total = res [ " total_count " ]
to = from + issues . size - 1
puts " #{ from } - #{ to } / #{ total } "
issues . each_with_index do | x , i |
id = " # #{ x [ " id " ] } " . color ( * PRIORITIES [ x [ " priority " ] [ " name " ] ] )
2015-02-23 12:30:24 +03:00
puts " #{ '%2d' % i } #{ id } #{ x [ " priority " ] [ " name " ] [ 0 ] } #{ status_char ( x [ " status " ] ) } #{ x [ " subject " ] [ 0 , 80 ] } "
2014-02-21 18:10:06 +04:00
end
2015-03-03 18:30:54 +03:00
} ,
" show " = > proc { | args |
2016-03-29 12:59:27 +03:00
if / \ A( \ d+) \ z / =~ args
id = $1 . to_i
id = @issues [ id ] [ " id " ] if @issues && id < @issues . size
@issue = id
elsif @issue
id = @issue
else
raise CommandSyntaxError
end
2014-02-21 18:10:06 +04:00
uri = " #{ REDMINE_BASE } /issues/ #{ id } "
uri = URI ( uri + " .json?include=children,attachments,relations,changesets,journals " )
2015-03-03 20:14:22 +03:00
res = JSON ( uri . read ( $openuri_options ) )
2014-02-21 18:10:06 +04:00
i = res [ " issue " ]
2014-12-24 07:26:18 +03:00
unless i [ " changesets " ]
abort " You don't have view_changesets permission "
end
2017-07-07 05:14:57 +03:00
unless i [ " custom_fields " ]
puts " The specified ticket \# #{ @issue } seems to be a feature ticket "
@issue = nil
next
end
2014-02-21 18:10:06 +04:00
id = " # #{ i [ " id " ] } " . color ( * PRIORITIES [ i [ " priority " ] [ " name " ] ] )
sio = StringIO . new
2018-08-13 15:42:55 +03:00
sio . set_encoding ( " utf-8 " )
2014-02-21 18:10:06 +04:00
sio . puts <<eom
2015-01-06 04:19:01 +03:00
#{i["subject"].color(bold: true, underscore: true)}
2014-02-21 18:10:06 +04:00
#{i["project"]["name"]} [#{i["tracker"]["name"]} #{id}] #{i["status"]["name"]} (#{i["created_on"]})
author : #{i["author"]["name"]}
assigned : #{i["assigned_to"].to_h["name"]}
eom
i [ " custom_fields " ] . each do | x |
sio . puts " %-10s: %s " % [ x [ " name " ] , x [ " value " ] ]
end
2019-12-20 03:19:39 +03:00
#res["attachments"].each do |x|
2014-02-21 18:10:06 +04:00
#end
sio . puts i [ " description " ]
sio . puts
2015-01-06 04:19:01 +03:00
sio . puts " = changesets " . color ( bold : true , underscore : true )
2014-12-24 07:26:18 +03:00
@changesets = [ ]
i [ " changesets " ] . each do | x |
@changesets << x [ " revision " ]
2015-01-06 04:19:01 +03:00
sio . puts " == #{ x [ " revision " ] } #{ x [ " committed_on " ] } #{ x [ " user " ] [ " name " ] rescue nil } " . color ( bold : true , underscore : true )
2014-12-24 07:26:18 +03:00
sio . puts x [ " comments " ]
2014-02-21 18:10:06 +04:00
end
2015-03-03 20:14:22 +03:00
@changesets = @changesets . sort . uniq
2014-12-23 16:04:06 +03:00
if i [ " journals " ] && ! i [ " journals " ] . empty?
2015-01-06 04:19:01 +03:00
sio . puts " = journals " . color ( bold : true , underscore : true )
2014-12-23 16:04:06 +03:00
i [ " journals " ] . each do | x |
2015-01-06 04:19:01 +03:00
sio . puts " == #{ x [ " user " ] [ " name " ] } ( #{ x [ " created_on " ] } ) " . color ( bold : true , underscore : true )
2014-12-23 16:04:06 +03:00
x [ " details " ] . each do | y |
sio . puts JSON ( y )
end
sio . puts x [ " notes " ]
2014-02-21 18:10:06 +04:00
end
end
more ( sio )
2015-03-03 18:30:54 +03:00
} ,
2014-02-21 18:10:06 +04:00
2015-03-03 18:30:54 +03:00
" rel " = > proc { | args |
2015-01-16 12:48:57 +03:00
# this feature requires custom redmine which allows add_related_issue API
2019-04-21 17:24:38 +03:00
case args
when / \ Ar?( \ d+) \ z / # SVN
rev = $1
2020-01-01 09:06:18 +03:00
uri = URI ( " #{ REDMINE_BASE } /projects/ruby-master/repository/trunk/revisions/ #{ rev } /issues.json " )
2019-04-21 17:24:38 +03:00
when / \ A \ h{7,40} \ z / # Git
rev = args
2020-01-01 09:06:18 +03:00
uri = URI ( " #{ REDMINE_BASE } /projects/ruby-master/repository/git/revisions/ #{ rev } /issues.json " )
2019-04-21 17:24:38 +03:00
else
raise CommandSyntaxError
end
2015-03-03 18:30:54 +03:00
unless @issue
puts " ticket not selected "
next
end
2019-04-21 17:24:38 +03:00
2015-01-16 12:48:57 +03:00
Net :: HTTP . start ( uri . host , uri . port , http_options ) do | http |
res = http . post ( uri . path , " issue_id= #@issue " ,
'X-Redmine-API-Key' = > REDMINE_API_KEY )
2016-03-29 12:59:27 +03:00
begin
res . value
rescue
2016-10-27 10:34:32 +03:00
if $! . respond_to? ( :response ) && $! . response . is_a? ( Net :: HTTPConflict )
$stderr . puts " the revision has already related to the ticket "
else
2019-04-21 17:24:38 +03:00
$stderr . puts " #{ $! . class } : #{ $! . message } \n \n deployed redmine doesn't have https://github.com/ruby/bugs.ruby-lang.org/commit/01fbba60d68cb916ddbccc8a8710e68c5217171d \n ask naruse or hsbt "
2016-10-27 10:34:32 +03:00
end
2016-04-26 17:43:50 +03:00
next
2016-03-29 12:59:27 +03:00
end
2015-01-16 12:48:57 +03:00
puts res . body
2016-03-29 19:55:55 +03:00
@changesets << rev
2015-05-25 16:38:00 +03:00
class << @changesets
remove_method ( :validated ) rescue nil
end
2015-01-16 12:48:57 +03:00
end
2015-03-03 18:30:54 +03:00
} ,
2015-01-16 12:48:57 +03:00
2015-03-03 18:30:54 +03:00
" backport " = > proc { | args |
2015-01-16 12:48:57 +03:00
# this feature implies backport command which wraps tool/merger.rb
2016-11-11 18:43:43 +03:00
raise CommandSyntaxError unless args . empty?
2014-02-22 15:29:21 +04:00
unless @issue
puts " ticket not selected "
next
end
2014-02-21 18:10:06 +04:00
puts backport_command_string
2015-03-03 18:30:54 +03:00
} ,
2014-02-21 18:10:06 +04:00
2015-03-03 18:30:54 +03:00
" done " = > proc { | args |
2023-02-01 16:49:19 +03:00
raise CommandSyntaxError unless / \ A( \ d+)?(?: *by ( \ h+))?(?: \ s*-- +(.*))? \ z / =~ args
2021-02-02 13:15:45 +03:00
notes = $3
2014-02-22 17:43:16 +04:00
notes . strip! if notes
2021-02-02 13:15:45 +03:00
rev = $2
2014-02-21 18:10:06 +04:00
if $1
2014-02-22 15:29:21 +04:00
i = $1 . to_i
2014-02-21 18:10:06 +04:00
i = @issues [ i ] [ " id " ] if @issues && i < @issues . size
@issue = i
end
2014-02-22 15:29:21 +04:00
unless @issue
puts " ticket not selected "
next
end
2014-02-21 18:10:06 +04:00
2021-02-02 13:15:45 +03:00
if rev
elsif system ( " svn info #{ RUBY_REPO_PATH & . shellescape } " , % i ( out err ) = > IO :: NULL ) # SVN
2019-06-16 05:39:12 +03:00
if ( log = find_svn_log ( " # #@issue ] " ) ) && ( / revision="(?<rev> \ d+) / =~ log )
2019-04-28 13:33:41 +03:00
rev = " r #{ rev } "
end
else # Git
if log = find_git_log ( " # #@issue ] " )
/ ^commit (?<rev> \ h{40})$ / =~ log
end
end
if log && rev
2014-02-22 17:43:16 +04:00
str = log [ / merge revision \ (s \ ) ([^:]+)(?=:) / ]
2020-03-13 16:27:54 +03:00
if str
str . insert ( 5 , " d " )
str = " ruby_ #{ TARGET_VERSION . tr ( '.' , '_' ) } #{ rev } #{ str } . "
else
str = " ruby_ #{ TARGET_VERSION . tr ( '.' , '_' ) } #{ rev } . "
end
2014-02-22 17:43:16 +04:00
if notes
str << " \n "
str << notes
end
notes = str
2021-02-02 13:15:45 +03:00
elsif rev && has_commit ( rev , " ruby_ #{ TARGET_VERSION . tr ( '.' , '_' ) } " )
# Backport commit's log doesn't have the issue number.
# Instead of that manually it's provided.
notes = " ruby_ #{ TARGET_VERSION . tr ( '.' , '_' ) } commit: #{ rev } . "
2014-02-22 17:43:16 +04:00
else
puts " no commit is found whose log include # #@issue "
next
end
puts notes
2014-02-21 18:10:06 +04:00
uri = URI ( " #{ REDMINE_BASE } /issues/ #{ @issue } .json " )
2014-02-22 15:29:21 +04:00
Net :: HTTP . start ( uri . host , uri . port , http_options ) do | http |
2014-02-21 18:10:06 +04:00
res = http . get ( uri . path )
data = JSON ( res . body )
h = data [ " issue " ] [ " custom_fields " ] . find { | x | x [ " id " ] == 5 }
2017-03-12 21:31:38 +03:00
if h and val = h [ " value " ] and val != " "
2014-02-21 18:10:06 +04:00
case val [ / (?: \ A|, ) #{ Regexp . quote TARGET_VERSION } : ([^,]+) / , 1 ]
2014-07-02 10:39:06 +04:00
when 'REQUIRED' , 'UNKNOWN' , 'DONTNEED' , 'WONTFIX'
2015-01-22 12:05:53 +03:00
val [ $~ . offset ( 1 ) [ 0 ] ... $~ . offset ( 1 ) [ 1 ] ] = 'DONE'
2014-02-21 18:10:06 +04:00
when 'DONE' # , /\A\d+\z/
puts 'already backport is done'
next # already done
when nil
val << " , #{ TARGET_VERSION } : DONE "
else
raise " unknown status ' # $1' "
end
else
2017-03-12 21:31:38 +03:00
val = " #{ TARGET_VERSION } : DONE "
2014-02-21 18:10:06 +04:00
end
data = { " issue " = > { " custom_fields " = > [ { " id " = > 5 , " value " = > val } ] } }
data [ 'issue' ] [ 'notes' ] = notes if notes
res = http . put ( uri . path , JSON ( data ) ,
'X-Redmine-API-Key' = > REDMINE_API_KEY ,
'Content-Type' = > 'application/json' )
res . value
show_last_journal ( http , uri )
end
2015-03-03 18:30:54 +03:00
} ,
" close " = > proc { | args |
raise CommandSyntaxError unless / \ A( \ d+)? \ z / =~ args
2014-02-21 18:10:06 +04:00
if $1
i = $1 . to_i
i = @issues [ i ] [ " id " ] if @issues && i < @issues . size
@issue = i
end
2014-02-22 15:29:21 +04:00
unless @issue
puts " ticket not selected "
next
end
2014-02-21 18:10:06 +04:00
uri = URI ( " #{ REDMINE_BASE } /issues/ #{ @issue } .json " )
2014-02-22 15:29:21 +04:00
Net :: HTTP . start ( uri . host , uri . port , http_options ) do | http |
2014-02-21 18:10:06 +04:00
data = { " issue " = > { " status_id " = > STATUS_CLOSE } }
res = http . put ( uri . path , JSON ( data ) ,
'X-Redmine-API-Key' = > REDMINE_API_KEY ,
'Content-Type' = > 'application/json' )
res . value
show_last_journal ( http , uri )
end
2015-03-03 18:30:54 +03:00
} ,
" last " = > proc { | args |
raise CommandSyntaxError unless / \ A( \ d+)? \ z / =~ args
2014-02-21 18:10:06 +04:00
if $1
i = $1 . to_i
i = @issues [ i ] [ " id " ] if @issues && i < @issues . size
@issue = i
end
2014-02-22 15:29:21 +04:00
unless @issue
puts " ticket not selected "
next
end
2014-02-21 18:10:06 +04:00
uri = URI ( " #{ REDMINE_BASE } /issues/ #{ @issue } .json " )
2014-02-22 15:29:21 +04:00
Net :: HTTP . start ( uri . host , uri . port , http_options ) do | http |
2014-02-21 18:10:06 +04:00
show_last_journal ( http , uri )
end
2015-03-03 18:30:54 +03:00
} ,
" ! " = > proc { | args |
system ( args . strip )
} ,
" quit " = > proc { | args |
raise CommandSyntaxError unless args . empty?
2014-02-21 18:10:06 +04:00
exit
2015-03-03 18:30:54 +03:00
} ,
" exit " = > " quit " ,
" help " = > proc { | args |
2015-01-20 06:59:03 +03:00
puts 'ls [PAGE] ' . color ( bold : true ) + ' show all required tickets'
2015-03-03 10:58:39 +03:00
puts '[show] TICKET ' . color ( bold : true ) + ' show the detail of the TICKET, and select it'
2015-03-03 18:30:54 +03:00
puts 'backport ' . color ( bold : true ) + ' show the option of selected ticket for merger.rb'
2015-01-20 05:31:50 +03:00
puts 'rel REVISION ' . color ( bold : true ) + ' add the selected ticket as related to the REVISION'
2014-02-22 15:29:21 +04:00
puts 'done [TICKET] [-- NOTE]' . color ( bold : true ) + ' set Backport field of the TICKET to DONE'
puts 'close [TICKET] ' . color ( bold : true ) + ' close the TICKET'
puts 'last [TICKET] ' . color ( bold : true ) + ' show the last journal of the TICKET'
2015-01-27 10:04:38 +03:00
puts '! COMMAND ' . color ( bold : true ) + ' execute COMMAND'
2015-03-03 18:30:54 +03:00
}
}
list = Abbrev . abbrev ( commands . keys )
@issues = nil
@issue = nil
@changesets = nil
while true
begin
l = Readline . readline " #{ ( '#' + @issue . to_s ) . color ( bold : true ) if @issue } > "
rescue Interrupt
break
end
break unless l
2015-03-24 10:49:02 +03:00
cmd , args = l . strip . split ( / \ s+| \ b / , 2 )
2015-03-03 18:30:54 +03:00
next unless cmd
if ( ! args || args . empty? ) && / \ A \ d+ \ z / =~ cmd
args = cmd
cmd = " show "
end
2016-07-06 19:05:57 +03:00
cmd = list [ cmd ]
2015-03-03 18:30:54 +03:00
if commands [ cmd ] . is_a? String
2016-07-06 19:05:57 +03:00
cmd = list [ commands [ cmd ] ]
2015-03-03 18:30:54 +03:00
end
begin
if cmd
2015-03-24 10:49:02 +03:00
commands [ cmd ] . call ( args )
2015-03-03 18:30:54 +03:00
else
raise CommandSyntaxError
end
rescue CommandSyntaxError
2014-02-21 18:10:06 +04:00
puts " error #{ l . inspect } "
end
end