git-issue 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/LICENSE +20 -0
- data/README.markdown +115 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/bin/git-issue +8 -0
- data/git-issue.gemspec +62 -0
- data/images/git-issue_screenshot-1.png +0 -0
- data/images/git-issue_screenshot-2.png +0 -0
- data/lib/git_issue.rb +96 -0
- data/lib/git_issue/base.rb +263 -0
- data/lib/git_issue/github.rb +362 -0
- data/lib/git_issue/redmine.rb +450 -0
- data/spec/git_issue/base_spec.rb +78 -0
- data/spec/git_issue/github_spec.rb +186 -0
- data/spec/git_issue/redmine_spec.rb +70 -0
- data/spec/git_issue_spec.rb +39 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +9 -0
- metadata +113 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Tomohito Ozaki
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
git-issue
|
2
|
+
====================================================
|
3
|
+
|
4
|
+
git subcommand of browse/modify issue traker's tickets.
|
5
|
+
|
6
|
+
now supporse Redmine,Github-issues
|
7
|
+
|
8
|
+
## ScreenShots
|
9
|
+
|
10
|
+
<img src='https://github.com/yuroyoro/git-issue/raw/master/images/git-issue_screenshot-1.png' width='600'/>
|
11
|
+
<img src='https://github.com/yuroyoro/git-issue/raw/master/images/git-issue_screenshot-2.png' width='600'/>
|
12
|
+
|
13
|
+
## Instration
|
14
|
+
|
15
|
+
$ git clone https://github.com/yuroyoro/git-issue.git
|
16
|
+
$ cd git-issue
|
17
|
+
$ rake install jeweler
|
18
|
+
$ rake build
|
19
|
+
$ gem install pkg/git-issue-<version>.gem
|
20
|
+
|
21
|
+
## Configuration
|
22
|
+
|
23
|
+
set type of issue traking system(redmine or github)
|
24
|
+
|
25
|
+
$ git config issue.type redmine
|
26
|
+
|
27
|
+
set url of issue traking system's api endopoint.
|
28
|
+
|
29
|
+
$ git config issue.url http://redmine.example.com
|
30
|
+
|
31
|
+
set api-key for accessing issue traking system.
|
32
|
+
|
33
|
+
$ git config issue.apikey FWeaj3I9laei03A....
|
34
|
+
|
35
|
+
set repository name if using github.
|
36
|
+
|
37
|
+
$ git config issue.repo gitterb
|
38
|
+
|
39
|
+
set your account name if using github.
|
40
|
+
|
41
|
+
$ git config issue.user yuroyoro
|
42
|
+
|
43
|
+
## Usage(Redmine)
|
44
|
+
|
45
|
+
git issue <command> [ticket_id] [<args>]
|
46
|
+
|
47
|
+
Commnads:
|
48
|
+
show s show given issue summary. if given no id, geuss id from current branch name.
|
49
|
+
list l listing issues.
|
50
|
+
mine m display issues that assigned to you.
|
51
|
+
commit c commit with filling issue subject to messsage.if given no id, geuss id from current branch name.
|
52
|
+
update u update issue properties. if given no id, geuss id from current branch name.
|
53
|
+
branch b checout to branch using specified issue id. if branch dose'nt exisits, create it. (ex ticket/id/<issue_id>)
|
54
|
+
publish pub push branch to remote repository and set upstream
|
55
|
+
rebase rb rebase branch onto specific newbase
|
56
|
+
help h show usage.
|
57
|
+
local loc listing local branches tickets
|
58
|
+
project prj listing ticket belongs to sspecified project
|
59
|
+
|
60
|
+
Options:
|
61
|
+
-a, --all update all paths in the index file
|
62
|
+
-f, --force force create branch
|
63
|
+
-v, --verbose show issue details
|
64
|
+
-n, --max-count=VALUE maximum number of issues
|
65
|
+
--oneline display short info
|
66
|
+
--raw-id output ticket number only
|
67
|
+
--remote=VALUE on publish, remote repository to push branch
|
68
|
+
--onto=VALUE on rebase, start new branch with HEAD equal to "newbase"
|
69
|
+
--debug debug print
|
70
|
+
-j, --supperss_journals show issue journals
|
71
|
+
-r, --supperss_relations show issue relations tickets
|
72
|
+
-c, --supperss_changesets show issue changesets
|
73
|
+
-q, --query=VALUE filter query of listing tickets
|
74
|
+
--subject=VALUE use the given value to update subject
|
75
|
+
--ratio=VALUE use the given value to update done-ratio(%)
|
76
|
+
--status=VALUE use the given value to update issue statues id
|
77
|
+
--priority=VALUE use the given value to update issue priority id
|
78
|
+
--tracker=VALUE use the given value to update tracker id
|
79
|
+
--assigned_to_id=VALUE use the given value to update assigned_to id
|
80
|
+
--category=VALUE use the given value to update category id
|
81
|
+
--fixed_version=VALUE use the given value to update fixed_version id
|
82
|
+
--custom_fields=VALUE value should be specifies '<custom_fields_id1>:<value2>,<custom_fields_id2>:<value2>, ...'
|
83
|
+
--notes=VALUE add notes to issue
|
84
|
+
|
85
|
+
## Usage(Redmine)
|
86
|
+
|
87
|
+
git issue <command> [ticket_id] [<args>]
|
88
|
+
|
89
|
+
Commnads:
|
90
|
+
show s show given issue summary. if given no id, geuss id from current branch name.
|
91
|
+
list l listing issues.
|
92
|
+
mine m display issues that assigned to you.
|
93
|
+
commit c commit with filling issue subject to messsage.if given no id, geuss id from current branch name.
|
94
|
+
update u update issue properties. if given no id, geuss id from current branch name.
|
95
|
+
branch b checout to branch using specified issue id. if branch dose'nt exisits, create it. (ex ticket/id/<issue_id>)
|
96
|
+
publish pub push branch to remote repository and set upstream
|
97
|
+
rebase rb rebase branch onto specific newbase
|
98
|
+
help h show usage.
|
99
|
+
|
100
|
+
Options:
|
101
|
+
-a, --all update all paths in the index file
|
102
|
+
-f, --force force create branch
|
103
|
+
-v, --verbose show issue details
|
104
|
+
-n, --max-count=VALUE maximum number of issues
|
105
|
+
--oneline display short info
|
106
|
+
--raw-id output ticket number only
|
107
|
+
--remote=VALUE on publish, remote repository to push branch
|
108
|
+
--onto=VALUE on rebase, start new branch with HEAD equal to "newbase"
|
109
|
+
--debug debug print
|
110
|
+
-s, --supperss_commentsc show issue journals
|
111
|
+
--state=VALUE Where 'state' is either 'open' or 'closed'
|
112
|
+
|
113
|
+
## Copyright
|
114
|
+
|
115
|
+
Copyright (c) 2011 Tomohito Ozaki. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "git-issue"
|
8
|
+
gem.summary = %Q{git extention command for issue tracker system.}
|
9
|
+
gem.description = %Q{git extention command for issue tracker system.}
|
10
|
+
gem.email = "ozaki@yuroyoro.com"
|
11
|
+
gem.homepage = "http://github.com/yuroyoro/git-issue"
|
12
|
+
gem.authors = ["Tomohito Ozaki"]
|
13
|
+
gem.add_development_dependency "rspec"
|
14
|
+
gem.add_development_dependency "activesupport"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rspec/core/rake_task'
|
22
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
23
|
+
# spec.libs << 'lib' << 'spec'
|
24
|
+
# spec.spec_files = FileList['spec/**/*_spec.rb']
|
25
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
26
|
+
end
|
27
|
+
|
28
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
29
|
+
# spec.libs << 'lib' << 'spec'
|
30
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
31
|
+
spec.rcov = true
|
32
|
+
end
|
33
|
+
|
34
|
+
task :spec => :check_dependencies
|
35
|
+
|
36
|
+
task :default => :spec
|
37
|
+
|
38
|
+
require 'rdoc/task'
|
39
|
+
Rake::RDocTask.new do |rdoc|
|
40
|
+
if File.exist?('VERSION')
|
41
|
+
version = File.read('VERSION')
|
42
|
+
else
|
43
|
+
version = ""
|
44
|
+
end
|
45
|
+
|
46
|
+
rdoc.rdoc_dir = 'rdoc'
|
47
|
+
rdoc.title = "git-issue #{version}"
|
48
|
+
rdoc.rdoc_files.include('README*')
|
49
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
50
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.7.0
|
data/bin/git-issue
ADDED
data/git-issue.gemspec
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{git-issue}
|
8
|
+
s.version = "0.7.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Tomohito Ozaki"]
|
12
|
+
s.date = %q{2012-02-23}
|
13
|
+
s.default_executable = %q{git-issue}
|
14
|
+
s.description = %q{git extention command for issue tracker system.}
|
15
|
+
s.email = %q{ozaki@yuroyoro.com}
|
16
|
+
s.executables = ["git-issue"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE",
|
19
|
+
"README.markdown"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
"LICENSE",
|
24
|
+
"README.markdown",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"bin/git-issue",
|
28
|
+
"git-issue.gemspec",
|
29
|
+
"images/git-issue_screenshot-1.png",
|
30
|
+
"images/git-issue_screenshot-2.png",
|
31
|
+
"lib/git_issue.rb",
|
32
|
+
"lib/git_issue/base.rb",
|
33
|
+
"lib/git_issue/github.rb",
|
34
|
+
"lib/git_issue/redmine.rb",
|
35
|
+
"spec/git_issue/base_spec.rb",
|
36
|
+
"spec/git_issue/github_spec.rb",
|
37
|
+
"spec/git_issue/redmine_spec.rb",
|
38
|
+
"spec/git_issue_spec.rb",
|
39
|
+
"spec/spec.opts",
|
40
|
+
"spec/spec_helper.rb"
|
41
|
+
]
|
42
|
+
s.homepage = %q{http://github.com/yuroyoro/git-issue}
|
43
|
+
s.require_paths = ["lib"]
|
44
|
+
s.rubygems_version = %q{1.5.2}
|
45
|
+
s.summary = %q{git extention command for issue tracker system.}
|
46
|
+
|
47
|
+
if s.respond_to? :specification_version then
|
48
|
+
s.specification_version = 3
|
49
|
+
|
50
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
51
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
52
|
+
s.add_development_dependency(%q<activesupport>, [">= 0"])
|
53
|
+
else
|
54
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
55
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
56
|
+
end
|
57
|
+
else
|
58
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
59
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
Binary file
|
Binary file
|
data/lib/git_issue.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
$KCODE="UTF8" if RUBY_VERSION < '1.9.0'
|
5
|
+
|
6
|
+
require 'pp'
|
7
|
+
require 'rubygems'
|
8
|
+
require 'uri'
|
9
|
+
require 'open-uri'
|
10
|
+
require "net/http"
|
11
|
+
require "net/https"
|
12
|
+
require "uri"
|
13
|
+
require 'fileutils'
|
14
|
+
require 'json'
|
15
|
+
require 'optparse'
|
16
|
+
require 'tempfile'
|
17
|
+
require 'active_support/all'
|
18
|
+
|
19
|
+
module GitIssue
|
20
|
+
class Command
|
21
|
+
attr_reader :name, :short_name, :description
|
22
|
+
def initialize(name, short_name, description)
|
23
|
+
@name, @short_name, @description = name, short_name, description
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module Helper
|
28
|
+
|
29
|
+
CONFIGURE_MESSAGE = <<-END
|
30
|
+
please set issue tracker %s.
|
31
|
+
|
32
|
+
%s
|
33
|
+
END
|
34
|
+
|
35
|
+
def configure_error(attr_name, example)
|
36
|
+
raise CONFIGURE_MESSAGE % [attr_name, example]
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def configured_value(name)
|
41
|
+
res = `git config issue.#{name}`
|
42
|
+
res.strip
|
43
|
+
end
|
44
|
+
|
45
|
+
def global_configured_value(name)
|
46
|
+
res = `git config --global #{name}`
|
47
|
+
res.strip
|
48
|
+
end
|
49
|
+
|
50
|
+
def its_klass_of(its_type)
|
51
|
+
case its_type
|
52
|
+
when /redmine/i then GitIssue::Redmine
|
53
|
+
when /github/i then GitIssue::Github
|
54
|
+
else
|
55
|
+
raise "unknown issue tracker type : #{its_type}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module_function :configured_value, :global_configured_value, :configure_error, :its_klass_of
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.main(argv)
|
63
|
+
status = true
|
64
|
+
|
65
|
+
begin
|
66
|
+
its_type = Helper.configured_value('type')
|
67
|
+
apikey = Helper.configured_value('apikey')
|
68
|
+
|
69
|
+
# Use global config for hub
|
70
|
+
if its_type.blank?
|
71
|
+
github_user = Helper.global_configured_value('github.user')
|
72
|
+
unless github_user.blank?
|
73
|
+
its_type = 'github'
|
74
|
+
apikey = Helper.global_configured_value('github.token')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
Helper.configure_error('type (redmine | github)', "git config issue.type redmine") if its_type.blank?
|
79
|
+
Helper.configure_error('apikey', "git config issue.apikey some_api_key") if apikey.blank?
|
80
|
+
|
81
|
+
its_klass = Helper.its_klass_of(its_type)
|
82
|
+
status = its_klass.new(ARGV).execute || true
|
83
|
+
rescue => e
|
84
|
+
puts e
|
85
|
+
puts e.backtrace.join("\n")
|
86
|
+
status = false
|
87
|
+
end
|
88
|
+
|
89
|
+
exit(status)
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
require File.dirname(__FILE__) + '/git_issue/base'
|
95
|
+
require File.dirname(__FILE__) + '/git_issue/redmine'
|
96
|
+
require File.dirname(__FILE__) + '/git_issue/github'
|
@@ -0,0 +1,263 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
class GitIssue::Base
|
4
|
+
include GitIssue::Helper
|
5
|
+
|
6
|
+
attr_reader :apikey, :command, :tickets, :options
|
7
|
+
attr_accessor :sysout, :syserr
|
8
|
+
|
9
|
+
def initialize(args, options = {})
|
10
|
+
|
11
|
+
@opt_parse_obj = opt_parser
|
12
|
+
args = parse_options(args)
|
13
|
+
|
14
|
+
@sysout = options[:sysout] || $stdout
|
15
|
+
@syserr = options[:syserr] || $stderr
|
16
|
+
|
17
|
+
split_ticket = lambda{|s| s.nil? || s.empty? ? nil : s.split(/,/).map{|v| v.strip.to_i} }
|
18
|
+
|
19
|
+
@tickets = []
|
20
|
+
cmd = args.shift || default_cmd
|
21
|
+
|
22
|
+
if cmd =~ /(\d+,?\s?)+/
|
23
|
+
@tickets = split_ticket.call(cmd)
|
24
|
+
cmd = :show
|
25
|
+
end
|
26
|
+
cmd = cmd.to_sym
|
27
|
+
|
28
|
+
@command = find_command(cmd)
|
29
|
+
|
30
|
+
exit_with_message("invalid command <#{cmd}>") unless @command
|
31
|
+
|
32
|
+
@tickets += args.map{|s| split_ticket.call(s)}.flatten.uniq
|
33
|
+
@tickets = [guess_ticket] if @tickets.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
def default_cmd
|
37
|
+
:list
|
38
|
+
end
|
39
|
+
|
40
|
+
def execute
|
41
|
+
if @tickets.nil? || @tickets.empty?
|
42
|
+
self.send(@command.name, @options)
|
43
|
+
else
|
44
|
+
@tickets.each do |ticket|
|
45
|
+
self.send(@command.name, @options.merge(:ticket_id => ticket))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
def help(options = {})
|
52
|
+
puts @opt_parse_obj.banner
|
53
|
+
puts " Commnads:"
|
54
|
+
puts usage
|
55
|
+
puts ""
|
56
|
+
puts " Options:"
|
57
|
+
puts @opt_parse_obj.summarize
|
58
|
+
end
|
59
|
+
|
60
|
+
def publish(options = {})
|
61
|
+
ticket, branch_name = ticket_and_branch(options)
|
62
|
+
remote = options[:remote] || "origin"
|
63
|
+
system "git push -u #{remote} #{branch_name}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def rebase(options = {})
|
67
|
+
raise '--onto is required.' unless options[:onto]
|
68
|
+
ticket, branch_name = ticket_and_branch(options)
|
69
|
+
onto = options[:onto]
|
70
|
+
|
71
|
+
cb = current_branch
|
72
|
+
|
73
|
+
system "git rebase --onto #{onto} #{onto} #{branch_name}"
|
74
|
+
system "git checkout #{cb}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def commands
|
78
|
+
[
|
79
|
+
GitIssue::Command.new(:show, :s, 'show given issue summary. if given no id, geuss id from current branch name.'),
|
80
|
+
GitIssue::Command.new(:list, :l, 'listing issues.'),
|
81
|
+
GitIssue::Command.new(:mine, :m, 'display issues that assigned to you.'),
|
82
|
+
GitIssue::Command.new(:commit, :c, 'commit with filling issue subject to messsage.if given no id, geuss id from current branch name.'),
|
83
|
+
GitIssue::Command.new(:add, :a, 'create issue.'),
|
84
|
+
GitIssue::Command.new(:update, :u, 'update issue properties. if given no id, geuss id from current branch name.'),
|
85
|
+
GitIssue::Command.new(:branch, :b, "checout to branch using specified issue id. if branch dose'nt exisits, create it. (ex ticket/id/<issue_id>)"),
|
86
|
+
|
87
|
+
GitIssue::Command.new(:publish,:pub, "push branch to remote repository and set upstream "),
|
88
|
+
GitIssue::Command.new(:rebase, :rb, "rebase branch onto specific newbase"),
|
89
|
+
|
90
|
+
GitIssue::Command.new(:help, :h, "show usage.")
|
91
|
+
]
|
92
|
+
end
|
93
|
+
|
94
|
+
def find_command(cmd)
|
95
|
+
cmd = cmd.to_sym
|
96
|
+
commands.find{|c| c.name == cmd || c.short_name == cmd }
|
97
|
+
end
|
98
|
+
|
99
|
+
def usage
|
100
|
+
commands.map{|c| "%-8s %s %s" % [c.name, c.short_name, c.description ] }.join("\n")
|
101
|
+
end
|
102
|
+
|
103
|
+
def time_ago_in_words(time)
|
104
|
+
t = Time.parse(time)
|
105
|
+
a = (Time.now - t).to_i
|
106
|
+
|
107
|
+
case a
|
108
|
+
when 0 then return 'just now'
|
109
|
+
when 1..59 then return a.to_s + '秒前'
|
110
|
+
when 60..119 then return '1分前'
|
111
|
+
when 120..3540 then return (a/60).to_i.to_s + '分前'
|
112
|
+
when 3541..7100 then return '1時間前'
|
113
|
+
when 7101..82800 then return ((a+99)/3600).to_i.to_s + '時間前'
|
114
|
+
when 82801..172000 then return '1日前'
|
115
|
+
when 172001..432000 then return ((a+800)/(60*60*24)).to_i.to_s + '日前'
|
116
|
+
else return ((a+800)/(60*60*24)).to_i.to_s + '日前'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def exit_with_message(msg, status=1)
|
121
|
+
err msg
|
122
|
+
exit(status)
|
123
|
+
end
|
124
|
+
|
125
|
+
BRANCH_NAME_FORMAT = "ticket/id/%s"
|
126
|
+
|
127
|
+
def ticket_branch(ticket_id)
|
128
|
+
BRANCH_NAME_FORMAT % ticket_id
|
129
|
+
end
|
130
|
+
|
131
|
+
def current_branch
|
132
|
+
%x(git branch -l | grep "*" | cut -d " " -f 2).strip
|
133
|
+
end
|
134
|
+
|
135
|
+
def guess_ticket
|
136
|
+
branch = current_branch
|
137
|
+
if branch =~ %r!id/(\d+)!
|
138
|
+
ticket = $1
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def ticket_and_branch(options)
|
143
|
+
if options[:ticket_id]
|
144
|
+
ticket = options[:ticket_id]
|
145
|
+
branch_name = ticket_branch(ticket)
|
146
|
+
else
|
147
|
+
branch_name = current_branch
|
148
|
+
ticket = guess_ticket
|
149
|
+
end
|
150
|
+
[ticket, branch_name]
|
151
|
+
end
|
152
|
+
|
153
|
+
def response_success?(response)
|
154
|
+
code = response.code.to_i
|
155
|
+
code >= 200 && code < 300
|
156
|
+
end
|
157
|
+
|
158
|
+
# this is unnecessary hacks for multibytes charactors handling...
|
159
|
+
def mlength(s)
|
160
|
+
width = 0
|
161
|
+
cnt = 0
|
162
|
+
s.split(//u).each{|c| cnt += 1 ;width += 1 if c.length > 1 }
|
163
|
+
cnt + width
|
164
|
+
end
|
165
|
+
|
166
|
+
# this is unnecessary hacks for multibytes charactors handling...
|
167
|
+
def mljust(s, n)
|
168
|
+
return "" unless s
|
169
|
+
cnt = 0
|
170
|
+
chars = []
|
171
|
+
|
172
|
+
s.split(//u).each do |c|
|
173
|
+
next if cnt > n
|
174
|
+
chars << c
|
175
|
+
cnt += 1
|
176
|
+
cnt += 1 if c.length > 1
|
177
|
+
end
|
178
|
+
if cnt > n
|
179
|
+
chars.pop
|
180
|
+
cnt -= 1
|
181
|
+
cnt -= 1 if chars.last.length > 1
|
182
|
+
end
|
183
|
+
chars << " " * (n - cnt) if n > cnt
|
184
|
+
chars.join
|
185
|
+
end
|
186
|
+
|
187
|
+
# for 1.8.6...
|
188
|
+
def mktmpdir(prefix_suffix=nil, tmpdir=nil)
|
189
|
+
case prefix_suffix
|
190
|
+
when nil
|
191
|
+
prefix = "d"
|
192
|
+
suffix = ""
|
193
|
+
when String
|
194
|
+
prefix = prefix_suffix
|
195
|
+
suffix = ""
|
196
|
+
when Array
|
197
|
+
prefix = prefix_suffix[0]
|
198
|
+
suffix = prefix_suffix[1]
|
199
|
+
else
|
200
|
+
raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
|
201
|
+
end
|
202
|
+
tmpdir ||= Dir.tmpdir
|
203
|
+
t = Time.now.strftime("%Y%m%d")
|
204
|
+
n = nil
|
205
|
+
begin
|
206
|
+
path = "#{tmpdir}/#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
|
207
|
+
path << "-#{n}" if n
|
208
|
+
path << suffix
|
209
|
+
Dir.mkdir(path, 0700)
|
210
|
+
rescue Errno::EEXIST
|
211
|
+
n ||= 0
|
212
|
+
n += 1
|
213
|
+
retry
|
214
|
+
end
|
215
|
+
|
216
|
+
if block_given?
|
217
|
+
begin
|
218
|
+
yield path
|
219
|
+
ensure
|
220
|
+
FileUtils.remove_entry_secure path
|
221
|
+
end
|
222
|
+
else
|
223
|
+
path
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def to_date(d)
|
228
|
+
Date.parse(d).strftime('%Y/%m/%d') rescue d
|
229
|
+
end
|
230
|
+
|
231
|
+
def parse_options(args)
|
232
|
+
@options = {}
|
233
|
+
@opt_parse_obj.parse!(args)
|
234
|
+
args
|
235
|
+
end
|
236
|
+
|
237
|
+
def opt_parser
|
238
|
+
OptionParser.new{|opts|
|
239
|
+
opts.banner = 'git issue <command> [ticket_id] [<args>]'
|
240
|
+
opts.on("--all", "-a", "update all paths in the index file "){ @options[:all] = true }
|
241
|
+
opts.on("--force", "-f", "force create branch"){ @options[:force] = true }
|
242
|
+
opts.on("--verbose", "-v", "show issue details"){|v| @options[:verbose] = true}
|
243
|
+
opts.on("--max-count=VALUE", "-n=VALUE", "maximum number of issues "){|v| @options[:max_count] = v.to_i}
|
244
|
+
opts.on("--oneline", "display short info"){|v| @options[:oneline] = true}
|
245
|
+
opts.on("--raw-id", "output ticket number only"){|v| @options[:raw_id] = true}
|
246
|
+
opts.on("--remote=VALUE", 'on publish, remote repository to push branch ') {|v| @options[:remote] = v}
|
247
|
+
opts.on("--onto=VALUE", 'on rebase, start new branch with HEAD equal to "newbase" ') {|v| @options[:onto] = v}
|
248
|
+
|
249
|
+
opts.on("--debug", "debug print"){@debug= true }
|
250
|
+
}
|
251
|
+
|
252
|
+
end
|
253
|
+
|
254
|
+
def puts(msg)
|
255
|
+
@sysout.puts msg
|
256
|
+
end
|
257
|
+
|
258
|
+
def err(msg)
|
259
|
+
@syserr.puts msg
|
260
|
+
end
|
261
|
+
|
262
|
+
end
|
263
|
+
|