ruby-jira-cli 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +47 -0
- data/bin/jira +26 -0
- data/lib/jira/api.rb +76 -0
- data/lib/jira/auth_api.rb +11 -0
- data/lib/jira/command.rb +60 -0
- data/lib/jira/commands/all.rb +72 -0
- data/lib/jira/commands/assign.rb +65 -0
- data/lib/jira/commands/attachments.rb +45 -0
- data/lib/jira/commands/checkout.rb +87 -0
- data/lib/jira/commands/comment/add.rb +52 -0
- data/lib/jira/commands/comment/delete.rb +80 -0
- data/lib/jira/commands/comment/list.rb +72 -0
- data/lib/jira/commands/comment/update.rb +88 -0
- data/lib/jira/commands/comment.rb +14 -0
- data/lib/jira/commands/delete.rb +92 -0
- data/lib/jira/commands/describe.rb +64 -0
- data/lib/jira/commands/install.rb +121 -0
- data/lib/jira/commands/link.rb +94 -0
- data/lib/jira/commands/log/add.rb +52 -0
- data/lib/jira/commands/log/delete.rb +80 -0
- data/lib/jira/commands/log/list.rb +69 -0
- data/lib/jira/commands/log/update.rb +89 -0
- data/lib/jira/commands/log.rb +13 -0
- data/lib/jira/commands/new.rb +174 -0
- data/lib/jira/commands/rename.rb +53 -0
- data/lib/jira/commands/sprint.rb +109 -0
- data/lib/jira/commands/tickets.rb +55 -0
- data/lib/jira/commands/transition.rb +97 -0
- data/lib/jira/commands/version.rb +10 -0
- data/lib/jira/commands/vote/add.rb +43 -0
- data/lib/jira/commands/vote/delete.rb +46 -0
- data/lib/jira/commands/vote/list.rb +59 -0
- data/lib/jira/commands/vote.rb +12 -0
- data/lib/jira/commands/watch/add.rb +43 -0
- data/lib/jira/commands/watch/delete.rb +46 -0
- data/lib/jira/commands/watch/list.rb +59 -0
- data/lib/jira/commands/watch.rb +12 -0
- data/lib/jira/constants.rb +7 -0
- data/lib/jira/core.rb +101 -0
- data/lib/jira/exceptions.rb +3 -0
- data/lib/jira/format.rb +78 -0
- data/lib/jira/sprint_api.rb +33 -0
- data/lib/jira.rb +19 -0
- metadata +202 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
module Jira
|
2
|
+
class Log < Thor
|
3
|
+
|
4
|
+
desc 'update', 'Updates work logged on the input ticket'
|
5
|
+
def update(ticket=Jira::Core.ticket)
|
6
|
+
Command::Log::Update.new(ticket).run
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module Command
|
12
|
+
module Log
|
13
|
+
class Update < Base
|
14
|
+
|
15
|
+
attr_accessor :ticket
|
16
|
+
|
17
|
+
def initialize(ticket=Jira::Core.ticket)
|
18
|
+
self.ticket = ticket
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
return unless logs?
|
23
|
+
api.patch endpoint,
|
24
|
+
params: params,
|
25
|
+
success: on_success,
|
26
|
+
failure: on_failure
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def params
|
32
|
+
{ timeSpent: updated_time_spent }
|
33
|
+
end
|
34
|
+
|
35
|
+
def updated_time_spent
|
36
|
+
io.ask('Updated time spent?')
|
37
|
+
end
|
38
|
+
|
39
|
+
def logs?
|
40
|
+
if json.empty?
|
41
|
+
puts "Ticket #{ticket} has no work logged."
|
42
|
+
return false
|
43
|
+
end
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
def endpoint
|
48
|
+
"issue/#{ticket}/worklog/#{to_update['id']}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def on_success
|
52
|
+
->{ puts "Successfully updated #{to_update['timeSpent']}." }
|
53
|
+
end
|
54
|
+
|
55
|
+
def on_failure
|
56
|
+
->{ puts "No logged work updated." }
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_update
|
60
|
+
@to_delete ||= logs[
|
61
|
+
io.select("Select a worklog to update:", logs.keys)
|
62
|
+
]
|
63
|
+
end
|
64
|
+
|
65
|
+
def logs
|
66
|
+
@logs ||= (
|
67
|
+
logs = {}
|
68
|
+
json.each do |log|
|
69
|
+
logs[description_for(log)] = log
|
70
|
+
end
|
71
|
+
logs
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
def description_for(log)
|
76
|
+
author = log['updateAuthor']['displayName']
|
77
|
+
updated_at = Jira::Format.time(Time.parse(log['updated']))
|
78
|
+
time_spent = log['timeSpent']
|
79
|
+
"#{author} @ #{updated_at}: #{time_spent}"
|
80
|
+
end
|
81
|
+
|
82
|
+
def json
|
83
|
+
@json ||= api.get("issue/#{ticket}/worklog")['worklogs']
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'jira/commands/log/add'
|
2
|
+
require 'jira/commands/log/delete'
|
3
|
+
require 'jira/commands/log/list'
|
4
|
+
require 'jira/commands/log/update'
|
5
|
+
|
6
|
+
module Jira
|
7
|
+
class CLI < Thor
|
8
|
+
|
9
|
+
desc 'log <command>', 'Commands for logging operations in JIRA'
|
10
|
+
subcommand 'log', Log
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
module Jira
|
2
|
+
class CLI < Thor
|
3
|
+
|
4
|
+
desc "new", "Creates a new ticket in JIRA and checks out the git branch"
|
5
|
+
method_option :project, aliases: "-p", type: :string, default: nil, banner: "PROJECT"
|
6
|
+
method_option :components, aliases: "-c", type: :array, default: nil, lazy_default: [], banner: "COMPONENTS"
|
7
|
+
method_option :issuetype, aliases: "-i", type: :string, default: nil, banner: "ISSUETYPE"
|
8
|
+
method_option :parent, type: :string, default: nil, lazy_default: "", banner: "PARENT"
|
9
|
+
method_option :summary, aliases: "-s", type: :string, default: nil, banner: "SUMMARY"
|
10
|
+
method_option :description, aliases: "-d", type: :string, default: nil, lazy_default: "", banner: "DESCRIPTION"
|
11
|
+
method_option :assignee, aliases: "-a", type: :string, default: nil, lazy_default: "auto", banner: "ASSIGNEE"
|
12
|
+
def new
|
13
|
+
Command::New.new(options).run
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
module Command
|
19
|
+
class New < Base
|
20
|
+
|
21
|
+
attr_accessor :options
|
22
|
+
|
23
|
+
def initialize(options)
|
24
|
+
self.options = options
|
25
|
+
end
|
26
|
+
|
27
|
+
def run
|
28
|
+
return if metadata.empty?
|
29
|
+
return if project.nil? || project.empty?
|
30
|
+
return if project_metadata.empty?
|
31
|
+
components # Select components if any after a project
|
32
|
+
return if issue_type.nil? || issue_type.empty?
|
33
|
+
return if assign_parent? && parent.empty?
|
34
|
+
return if summary.empty?
|
35
|
+
|
36
|
+
api.post 'issue',
|
37
|
+
params: params,
|
38
|
+
success: on_success,
|
39
|
+
failure: on_failure
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attr_accessor :ticket
|
45
|
+
|
46
|
+
def params
|
47
|
+
{
|
48
|
+
fields: {
|
49
|
+
project: { id: project['id'] },
|
50
|
+
issuetype: { id: issue_type['id'] },
|
51
|
+
summary: summary,
|
52
|
+
description: description,
|
53
|
+
parent: @parent.nil? ? {} : { key: @parent },
|
54
|
+
components: @components.nil? ? [] : @components
|
55
|
+
}
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def on_success
|
60
|
+
->(json) do
|
61
|
+
self.ticket = json['key']
|
62
|
+
io.say("Ticket #{ticket} created.")
|
63
|
+
assign? if options.empty? || !options['assignee'].nil?
|
64
|
+
create_branch? && checkout_branch? if options.empty?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def assign?
|
69
|
+
Command::Assign.new(ticket, options).run if !options['assignee'].nil? || io.yes?('Assign?')
|
70
|
+
end
|
71
|
+
|
72
|
+
def create_branch?
|
73
|
+
return false if io.no?("Create branch?")
|
74
|
+
`git branch #{ticket} 2> /dev/null`
|
75
|
+
true
|
76
|
+
end
|
77
|
+
|
78
|
+
def checkout_branch?
|
79
|
+
return false if io.no?("Check-out branch?")
|
80
|
+
`git checkout #{ticket} 2> /dev/null`
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
def on_failure
|
85
|
+
->{ puts "No ticket created." }
|
86
|
+
end
|
87
|
+
|
88
|
+
def metadata
|
89
|
+
# TODO: {} on 200 but jira error
|
90
|
+
@metadata ||= api.get('issue/createmeta')
|
91
|
+
end
|
92
|
+
|
93
|
+
def project
|
94
|
+
@project ||= projects[
|
95
|
+
options['project'] || io.select("Select a project:", projects.keys)
|
96
|
+
]
|
97
|
+
end
|
98
|
+
|
99
|
+
def projects
|
100
|
+
@projects ||= (
|
101
|
+
projects = {}
|
102
|
+
metadata['projects'].each do |project|
|
103
|
+
projects[project['name']] = {
|
104
|
+
'id' => project['id'],
|
105
|
+
'issues' => project['issuetypes']
|
106
|
+
}
|
107
|
+
end
|
108
|
+
projects
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
def project_metadata
|
113
|
+
id = project['id']
|
114
|
+
@project_metadata ||= api.get("project/#{id}")
|
115
|
+
end
|
116
|
+
|
117
|
+
def components
|
118
|
+
@components ||= (
|
119
|
+
components = {}
|
120
|
+
project_metadata['components'].each do |component|
|
121
|
+
components[component['name']] = { 'id' => component['id'] }
|
122
|
+
end
|
123
|
+
unless components.empty?
|
124
|
+
if options['components'].nil?
|
125
|
+
components = io.multi_select("Select component(s):", components)
|
126
|
+
else
|
127
|
+
components.select! { |k| options['components'].include?(k) }
|
128
|
+
components = components.values
|
129
|
+
end
|
130
|
+
end
|
131
|
+
components.to_a
|
132
|
+
)
|
133
|
+
end
|
134
|
+
|
135
|
+
def assign_parent?
|
136
|
+
return false unless issue_type['subtask']
|
137
|
+
return false if options['parent'].nil? && io.no?('Set parent of subtask?')
|
138
|
+
true
|
139
|
+
end
|
140
|
+
|
141
|
+
def parent
|
142
|
+
@parent ||= options['parent'] || io.ask('Subtask parent:', default: Jira::Core.ticket)
|
143
|
+
end
|
144
|
+
|
145
|
+
def issue_type
|
146
|
+
@issue_type ||= issue_types[
|
147
|
+
options['issuetype'] || io.select("Select an issue type:", issue_types.keys)
|
148
|
+
]
|
149
|
+
end
|
150
|
+
|
151
|
+
def issue_types
|
152
|
+
@issue_types ||= (
|
153
|
+
issue_types = {}
|
154
|
+
project['issues'].each do |issue_type|
|
155
|
+
issue_types[issue_type['name']] = issue_type
|
156
|
+
end
|
157
|
+
issue_types
|
158
|
+
)
|
159
|
+
end
|
160
|
+
|
161
|
+
def summary
|
162
|
+
@summary ||= options['summary'] || io.ask("Summary:", default: '')
|
163
|
+
end
|
164
|
+
|
165
|
+
def description
|
166
|
+
@description ||= (
|
167
|
+
description = options['description'] || (io.ask("Description:", default: '') if options['summary'].nil?)
|
168
|
+
description ||= ""
|
169
|
+
)
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Jira
|
2
|
+
class CLI < Thor
|
3
|
+
|
4
|
+
desc "rename", "Updates the summary of the input ticket"
|
5
|
+
method_option :summary, aliases: "-s", type: :string, default: nil, lazy_default: "", banner: "SUMMARY"
|
6
|
+
def rename(ticket=Jira::Core.ticket)
|
7
|
+
Command::Rename.new(ticket, options).run
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
module Command
|
13
|
+
class Rename < Base
|
14
|
+
|
15
|
+
attr_accessor :ticket, :options
|
16
|
+
|
17
|
+
def initialize(ticket, options)
|
18
|
+
self.ticket = ticket
|
19
|
+
self.options = options
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
return if ticket.empty?
|
24
|
+
return if summary.empty?
|
25
|
+
api.patch "issue/#{ticket}",
|
26
|
+
params: params,
|
27
|
+
success: on_success,
|
28
|
+
failure: on_failure
|
29
|
+
end
|
30
|
+
|
31
|
+
def params
|
32
|
+
{
|
33
|
+
fields: {
|
34
|
+
summary: summary
|
35
|
+
}
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def on_success
|
40
|
+
->{ puts "Successfully updated ticket #{ticket}'s summary." }
|
41
|
+
end
|
42
|
+
|
43
|
+
def on_failure
|
44
|
+
->{ puts "No change made to ticket #{ticket}." }
|
45
|
+
end
|
46
|
+
|
47
|
+
def summary
|
48
|
+
@summary ||= options['summary'] || io.ask("New summary for ticket #{ticket}:", default: '')
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Jira
|
2
|
+
class CLI < Thor
|
3
|
+
|
4
|
+
desc "sprint", "Lists sprint info"
|
5
|
+
def sprint(active = false)
|
6
|
+
Command::Sprint.new(active).run
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module Command
|
12
|
+
class Sprint < Base
|
13
|
+
|
14
|
+
attr_accessor :active
|
15
|
+
|
16
|
+
def initialize(active)
|
17
|
+
self.active = active
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def run
|
22
|
+
return if rapid_view.empty?
|
23
|
+
return if no_sprints?
|
24
|
+
return if sprint.empty?
|
25
|
+
if active == active
|
26
|
+
sprint_id = info['sprint']['id']
|
27
|
+
jql = "sprint = #{sprint_id}"
|
28
|
+
Command::Tickets.new(jql).run
|
29
|
+
else
|
30
|
+
render_table(
|
31
|
+
[ 'Sprint', 'State' ],
|
32
|
+
[ [ info['sprint']['name'], info['sprint']['state'] ] ]
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def no_sprints?
|
40
|
+
if sprints.empty?
|
41
|
+
puts "The #{rapid_view['name']} board has no sprints."
|
42
|
+
return true
|
43
|
+
end
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
def info
|
48
|
+
@info ||= sprint_api.sprint(rapid_view['id'], sprint['id'])
|
49
|
+
end
|
50
|
+
|
51
|
+
def sprint
|
52
|
+
@sprint ||= active_sprint || sprints[
|
53
|
+
io.select("Select a sprint:", sprints.keys[-10..-1])
|
54
|
+
]
|
55
|
+
end
|
56
|
+
|
57
|
+
def sprints
|
58
|
+
@sprints ||= (
|
59
|
+
sprints = {}
|
60
|
+
sprint_api.sprints(rapid_view['id'])['sprints'].each do |sprint|
|
61
|
+
sprints["#{sprint['name']}"] = {
|
62
|
+
'id' => sprint['id'],
|
63
|
+
'name' => sprint['name'],
|
64
|
+
'state' => sprint['state']
|
65
|
+
}
|
66
|
+
end
|
67
|
+
sprints
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
def active_sprint
|
72
|
+
sprints = {}
|
73
|
+
sprint_api.sprints(rapid_view['id'])['sprints'].each do |sprint|
|
74
|
+
if sprint['state'] == "ACTIVE"
|
75
|
+
sprints = {
|
76
|
+
'id' => sprint['id'],
|
77
|
+
'name' => sprint['name'],
|
78
|
+
'state' => sprint['state']
|
79
|
+
}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
sprints
|
83
|
+
end
|
84
|
+
|
85
|
+
def rapid_view
|
86
|
+
keys = rapid_views.keys
|
87
|
+
return '' if keys.empty?
|
88
|
+
# @rapid_view ||= rapid_views[
|
89
|
+
# io.select("Select a rapid view:", keys)
|
90
|
+
# ]
|
91
|
+
@rapid_view = {"id"=>15, "name"=>"Ruby Team"}
|
92
|
+
end
|
93
|
+
|
94
|
+
def rapid_views
|
95
|
+
@rapid_views ||= (
|
96
|
+
rapid_views = {}
|
97
|
+
sprint_api.rapid_views.each do |rapid_view|
|
98
|
+
rapid_views[rapid_view['name']] = {
|
99
|
+
'id' => rapid_view['id'],
|
100
|
+
'name' => rapid_view['name']
|
101
|
+
}
|
102
|
+
end
|
103
|
+
rapid_views
|
104
|
+
)
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Jira
|
2
|
+
class CLI < Thor
|
3
|
+
|
4
|
+
desc "tickets [jql]", "List the tickets of the input jql"
|
5
|
+
def tickets(jql="assignee=#{Jira::Core.username} AND status = \"In Progress\"")
|
6
|
+
Command::Tickets.new(jql).run
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module Command
|
12
|
+
class Tickets < Base
|
13
|
+
|
14
|
+
attr_accessor :jql
|
15
|
+
|
16
|
+
def initialize(jql)
|
17
|
+
self.jql = jql
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
return if jql.empty?
|
22
|
+
return if metadata.empty?
|
23
|
+
return unless metadata['errorMessages'].nil?
|
24
|
+
|
25
|
+
if rows.empty?
|
26
|
+
puts "There are no tickets for jql=#{jql}."
|
27
|
+
return
|
28
|
+
end
|
29
|
+
render_table(header, rows)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def header
|
35
|
+
[ 'Ticket', 'Assignee', 'Status', 'Summary']
|
36
|
+
end
|
37
|
+
|
38
|
+
def rows
|
39
|
+
metadata['issues'].map do |issue|
|
40
|
+
[
|
41
|
+
issue['key'],
|
42
|
+
(issue['fields']['assignee']['name'] unless issue['fields']['assignee'].nil?) || 'Unassigned',
|
43
|
+
(issue['fields']['status']['name'] unless issue['fields']['status'].nil?) || 'Unknown',
|
44
|
+
truncate(issue['fields']['summary'] || '', 45)
|
45
|
+
]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def metadata
|
50
|
+
@metadata ||= api.get("search?jql=#{jql}")
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Jira
|
2
|
+
class CLI < Thor
|
3
|
+
|
4
|
+
desc "transition", "Transitions the input ticket to the next state"
|
5
|
+
method_option :transition, aliases: "-t", type: :string, default: nil, lazy_default: "", banner: "TRANSITION"
|
6
|
+
method_option :resolution, aliases: "-r", type: :string, default: nil, lazy_default: "", banner: "RESOLUTION"
|
7
|
+
def transition(ticket=Jira::Core.ticket)
|
8
|
+
Command::Transition.new(ticket, options).run
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
module Command
|
14
|
+
class Transition < Base
|
15
|
+
|
16
|
+
attr_accessor :ticket, :options
|
17
|
+
|
18
|
+
def initialize(ticket, options)
|
19
|
+
self.ticket = ticket
|
20
|
+
self.options = options
|
21
|
+
end
|
22
|
+
|
23
|
+
def run
|
24
|
+
return if ticket.empty?
|
25
|
+
return if metadata.empty?
|
26
|
+
return unless metadata['errorMessages'].nil?
|
27
|
+
return if transition.nil? || transition.empty?
|
28
|
+
|
29
|
+
api.post "issue/#{ticket}/transitions",
|
30
|
+
params: params,
|
31
|
+
success: on_success,
|
32
|
+
failure: on_failure
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def params
|
38
|
+
{
|
39
|
+
transition: { id: transition[:id] },
|
40
|
+
fields: transition[:resolution?] ? { resolution: { name: resolution } } : {}
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def on_success
|
45
|
+
->{ puts "Transitioned ticket #{ticket} to #{transition_name}." }
|
46
|
+
end
|
47
|
+
|
48
|
+
def on_failure
|
49
|
+
->{ puts "Failed to transition ticket #{ticket}." }
|
50
|
+
end
|
51
|
+
|
52
|
+
def transition_name
|
53
|
+
transitions.invert[transition]
|
54
|
+
end
|
55
|
+
|
56
|
+
def transition
|
57
|
+
@transition ||= transitions[
|
58
|
+
options['transition'] || io.select("Transition #{ticket} to:", transitions.keys)
|
59
|
+
]
|
60
|
+
end
|
61
|
+
|
62
|
+
def transitions
|
63
|
+
@transitions ||= (
|
64
|
+
transitions = {}
|
65
|
+
metadata['transitions'].each do |transition|
|
66
|
+
transitions[transition['to']['name']] = {
|
67
|
+
id: transition['id'],
|
68
|
+
resolution?: !!transition['fields'].fetch('resolution', {})['required']
|
69
|
+
}
|
70
|
+
end
|
71
|
+
transitions
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
def metadata
|
76
|
+
@metadata ||= api.get("issue/#{ticket}/transitions?expand=transitions.fields")
|
77
|
+
end
|
78
|
+
|
79
|
+
def resolution
|
80
|
+
@resolution ||= resolutions[
|
81
|
+
options['resolution'] || io.select("Resolve #{ticket} as:", resolutions.keys)
|
82
|
+
]
|
83
|
+
end
|
84
|
+
|
85
|
+
def resolutions
|
86
|
+
@resolutions ||= (
|
87
|
+
resolutions = {}
|
88
|
+
api.get("resolution").each do |resolution|
|
89
|
+
resolutions[resolution['name']] = resolution['name']
|
90
|
+
end
|
91
|
+
resolutions
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Jira
|
2
|
+
class Vote < Thor
|
3
|
+
|
4
|
+
desc 'add', 'Vote for the input ticket'
|
5
|
+
def add(ticket=Jira::Core.ticket)
|
6
|
+
Command::Vote::Add.new(ticket).run
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module Command
|
12
|
+
module Vote
|
13
|
+
class Add < Base
|
14
|
+
|
15
|
+
attr_accessor :ticket
|
16
|
+
|
17
|
+
def initialize(ticket)
|
18
|
+
self.ticket = ticket
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
return if ticket.empty?
|
23
|
+
|
24
|
+
api.post "issue/#{ticket}/votes",
|
25
|
+
params: "\"#{Jira::Core.username}\"",
|
26
|
+
success: on_success,
|
27
|
+
failure: on_failure
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def on_success
|
33
|
+
->{ puts "Successfully voted for ticket #{ticket}" }
|
34
|
+
end
|
35
|
+
|
36
|
+
def on_failure
|
37
|
+
->{ puts "No vote cast." }
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Jira
|
2
|
+
class Vote < Thor
|
3
|
+
|
4
|
+
desc 'delete', 'Delete vote for the input ticket'
|
5
|
+
def delete(ticket=Jira::Core.ticket)
|
6
|
+
Command::Vote::Delete.new(ticket).run
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module Command
|
12
|
+
module Vote
|
13
|
+
class Delete < Base
|
14
|
+
|
15
|
+
attr_accessor :ticket
|
16
|
+
|
17
|
+
def initialize(ticket)
|
18
|
+
self.ticket = ticket
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
return if ticket.empty?
|
23
|
+
|
24
|
+
api.delete endpoint,
|
25
|
+
success: on_success,
|
26
|
+
failure: on_failure
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def endpoint
|
32
|
+
"issue/#{ticket}/votes?username=#{Jira::Core.username}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def on_success
|
36
|
+
->{ puts "Successfully removed vote from ticket #{ticket}" }
|
37
|
+
end
|
38
|
+
|
39
|
+
def on_failure
|
40
|
+
->{ puts "No unvote." }
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|