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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b229a4bc96644bd3e819673aa12a382530c9ed74
|
4
|
+
data.tar.gz: 0273cb796258b0e39599830647b9dedff8519479
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e14df53c00913ae286f0cd053f4f8d92adbb8526f2271d4201e217b72ba166e1a967796988c38b4851d40b0da1797f14a2609b8dcf4aee041aa3932ca6c8cee5
|
7
|
+
data.tar.gz: 6ee3d17a550cf5f974440e032af391edd58b5e108c4f60e610c96958e7a9c4890c4807086151350ec1fd05e60459f48e003324bd984e302ce88881f55423dede
|
data/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# JIRA CLI
|
2
|
+
|
3
|
+
Ruby gem CLI tool used to manage JIRA workflows leveraging git
|
4
|
+
|
5
|
+
* * *
|
6
|
+
|
7
|
+
### Available Commands
|
8
|
+
|
9
|
+
jira all # Describes all local branches that match JIRA ticketing syntax
|
10
|
+
jira assign # Assign a ticket to a user
|
11
|
+
jira attachments # View ticket attachments
|
12
|
+
jira checkout <ticket> # Checks out a ticket from JIRA in the git branch
|
13
|
+
jira comment <command> # Commands for comment operations in JIRA
|
14
|
+
jira delete # Deletes a ticket in JIRA and the git branch
|
15
|
+
jira describe # Describes the input ticket
|
16
|
+
jira help [COMMAND] # Describe available commands or one specific command
|
17
|
+
jira install # Guides the user through JIRA CLI installation
|
18
|
+
jira link # Creates a link between two tickets in JIRA
|
19
|
+
jira log <command> # Commands for logging operations in JIRA
|
20
|
+
jira new # Creates a new ticket in JIRA and checks out the git branch
|
21
|
+
jira rename # Updates the summary of the input ticket
|
22
|
+
jira sprint # Lists sprint info
|
23
|
+
jira tickets [jql] # List the in progress tickets of the input username (or jql)
|
24
|
+
jira transition # Transitions the input ticket to the next state
|
25
|
+
jira version # Displays the version
|
26
|
+
jira vote <command> # Commands for voting operations in JIRA
|
27
|
+
jira watch <command> # Commands for watching tickets in JIRA
|
28
|
+
|
29
|
+
### Gem Installation
|
30
|
+
|
31
|
+
Rubygems:
|
32
|
+
|
33
|
+
gem install ruby-jira-cli
|
34
|
+
|
35
|
+
Manually:
|
36
|
+
|
37
|
+
git clone git@github.com:ajmyers01/jira-cli.git
|
38
|
+
cd jira-cli
|
39
|
+
./scripts/install
|
40
|
+
|
41
|
+
### Project Installation
|
42
|
+
|
43
|
+
In order to use this tool, you'll need to run the installation script in the
|
44
|
+
git repository that you're managing via JIRA.
|
45
|
+
|
46
|
+
cd path/to/jira/repo
|
47
|
+
jira install
|
data/bin/jira
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'jira'
|
4
|
+
begin
|
5
|
+
Jira::CLI.start
|
6
|
+
File.delete(Jira::Core.rescue_cookie_path) if File.exist?(Jira::Core.rescue_cookie_path)
|
7
|
+
rescue Faraday::Error, UnauthorizedException
|
8
|
+
if Jira::CLI.new.try_install_cookie
|
9
|
+
if File.read(Jira::Core.rescue_cookie_path).count('r') < 3
|
10
|
+
puts "Re-running: jira #{ARGV.join(' ')}"
|
11
|
+
Process.waitpid(
|
12
|
+
Process.fork do
|
13
|
+
Process.exec("jira #{ARGV.join(' ')}")
|
14
|
+
end
|
15
|
+
)
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
end
|
19
|
+
puts "JIRA failed connect, you may need to rerun 'jira install'"
|
20
|
+
rescue GitException
|
21
|
+
puts "JIRA commands can only be run within a git repository."
|
22
|
+
rescue InstallationException
|
23
|
+
puts "Please run #{Jira::Format.summary('jira install')} before "\
|
24
|
+
"running this command."
|
25
|
+
rescue Interrupt
|
26
|
+
end
|
data/lib/jira/api.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module Jira
|
2
|
+
class API
|
3
|
+
|
4
|
+
def get(path, options={})
|
5
|
+
response = client.get(path, options[:params] || {}, headers)
|
6
|
+
process(response, options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def post(path, options={})
|
10
|
+
response = client.post(path, options[:params] || {}, headers)
|
11
|
+
process(response, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def patch(path, options={})
|
15
|
+
response = client.put(path, options[:params] || {}, headers)
|
16
|
+
process(response, options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def delete(path, options={})
|
20
|
+
response = client.delete(path, options[:params] || {}, headers)
|
21
|
+
process(response, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def process(response, options)
|
27
|
+
raise UnauthorizedException if response.status == 401
|
28
|
+
body = response.body || {}
|
29
|
+
json = (body if body.class == Hash) || {}
|
30
|
+
if response.success? && json['errorMessages'].nil?
|
31
|
+
respond_to(options[:success], body)
|
32
|
+
else
|
33
|
+
puts json['errorMessages'].join('. ') unless json['errorMessages'].nil?
|
34
|
+
respond_to(options[:failure], body)
|
35
|
+
end
|
36
|
+
body
|
37
|
+
end
|
38
|
+
|
39
|
+
def respond_to(block, body)
|
40
|
+
return if block.nil?
|
41
|
+
case block.arity
|
42
|
+
when 0
|
43
|
+
block.call
|
44
|
+
when 1
|
45
|
+
block.call(body)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def client
|
50
|
+
@client ||= Faraday.new(endpoint) do |faraday|
|
51
|
+
faraday.request :basic_auth, Jira::Core.username, Jira::Core.password unless Jira::Core.password.nil?
|
52
|
+
faraday.request :token_auth, Jira::Core.token unless Jira::Core.token.nil?
|
53
|
+
faraday.request :json
|
54
|
+
faraday.response :json
|
55
|
+
faraday.adapter :net_http
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def endpoint
|
60
|
+
"#{Jira::Core.url}/rest/api/2"
|
61
|
+
end
|
62
|
+
|
63
|
+
def headers
|
64
|
+
{ 'Content-Type' => 'application/json' }.merge(cookies)
|
65
|
+
end
|
66
|
+
|
67
|
+
def cookies
|
68
|
+
cookie = Jira::Core.cookie
|
69
|
+
unless cookie.empty?
|
70
|
+
return { 'cookie' => "#{cookie[:name]}=#{cookie[:value]}" }
|
71
|
+
end
|
72
|
+
{}
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
data/lib/jira/command.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# external dependencies
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
# internal dependencies
|
5
|
+
require 'jira/api'
|
6
|
+
require 'jira/sprint_api'
|
7
|
+
require 'jira/auth_api'
|
8
|
+
require 'jira/core'
|
9
|
+
|
10
|
+
module Jira
|
11
|
+
module Command
|
12
|
+
class Base
|
13
|
+
|
14
|
+
def run
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def api
|
21
|
+
@api ||= Jira::API.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def auth_api
|
25
|
+
@auth_api ||= Jira::AuthAPI.new
|
26
|
+
end
|
27
|
+
|
28
|
+
# TODO: Move this to relevant subcommand Base
|
29
|
+
def body(text=nil)
|
30
|
+
@body ||= (
|
31
|
+
comment = text || io.ask("Leave a comment for ticket #{ticket}:", default: 'Empty comment').strip
|
32
|
+
comment = comment.gsub(/\@[a-zA-Z]+/, '[~\0]') || comment
|
33
|
+
comment.gsub('[~@', '[~') || comment
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
def sprint_api
|
38
|
+
@sprint_api ||= Jira::SprintAPI.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def io
|
42
|
+
@io ||= TTY::Prompt.new
|
43
|
+
end
|
44
|
+
|
45
|
+
def render_table(header, rows)
|
46
|
+
puts TTY::Table.new(header, rows).render(:unicode, padding: [0, 1], multiline: true)
|
47
|
+
end
|
48
|
+
|
49
|
+
def truncate(string, limit=80)
|
50
|
+
return string if string.length < limit
|
51
|
+
string[0..limit-3] + '...'
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# load commands
|
59
|
+
commands_directory = File.join(File.dirname(__FILE__), 'commands', '*.rb')
|
60
|
+
Dir[commands_directory].each { |file| require file }
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Jira
|
2
|
+
class CLI < Thor
|
3
|
+
|
4
|
+
desc "all", "Describes all local branches that match JIRA ticketing syntax"
|
5
|
+
def all
|
6
|
+
Command::All.new.run
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module Command
|
12
|
+
class All < Base
|
13
|
+
|
14
|
+
def run
|
15
|
+
if tickets.empty?
|
16
|
+
puts 'No tickets'
|
17
|
+
return
|
18
|
+
end
|
19
|
+
return if json.empty?
|
20
|
+
return unless errors.empty?
|
21
|
+
render_table(header, rows)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def header
|
27
|
+
[ 'Ticket', 'Assignee', 'Status', 'Summary' ]
|
28
|
+
end
|
29
|
+
|
30
|
+
def rows
|
31
|
+
json['issues'].map do |issue|
|
32
|
+
[
|
33
|
+
issue['key'],
|
34
|
+
issue['fields']['assignee']['name'] || 'Unassigned',
|
35
|
+
issue['fields']['status']['name'] || 'Unknown',
|
36
|
+
truncate(issue['fields']['summary'], 45)
|
37
|
+
]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def errors
|
42
|
+
@errors ||= (json['errorMessages'] || []).join('. ')
|
43
|
+
end
|
44
|
+
|
45
|
+
def json
|
46
|
+
@json ||= api.get "search", params: params
|
47
|
+
end
|
48
|
+
|
49
|
+
def params
|
50
|
+
{
|
51
|
+
jql: "key in (#{tickets.join(',')})"
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def tickets
|
56
|
+
@tickets ||= (
|
57
|
+
tickets = []
|
58
|
+
branches.each do |branch|
|
59
|
+
ticket = branch.delete('*').strip
|
60
|
+
tickets << ticket if Jira::Core.ticket?(ticket, false)
|
61
|
+
end
|
62
|
+
tickets
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def branches
|
67
|
+
`git branch`.strip.split("\n")
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Jira
|
2
|
+
class CLI < Thor
|
3
|
+
|
4
|
+
desc "assign", "Assign a ticket to a user"
|
5
|
+
method_option :assignee, aliases: "-a", type: :string, default: nil, lazy_default: "auto", banner: "ASSIGNEE"
|
6
|
+
def assign(ticket=Jira::Core.ticket)
|
7
|
+
Command::Assign.new(ticket, options).run
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
module Command
|
13
|
+
class Assign < 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
|
+
api.patch path,
|
24
|
+
params: params,
|
25
|
+
success: on_success,
|
26
|
+
failure: on_failure
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def on_success
|
32
|
+
-> do
|
33
|
+
puts "Ticket #{ticket} assigned to #{name}."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_failure
|
38
|
+
->(json) do
|
39
|
+
message = (json['errors'] || {})['assignee']
|
40
|
+
puts message || "Ticket #{ticket} was not assigned."
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def path
|
45
|
+
"issue/#{ticket}/assignee"
|
46
|
+
end
|
47
|
+
|
48
|
+
def params
|
49
|
+
{ name: assignee }
|
50
|
+
end
|
51
|
+
|
52
|
+
def name
|
53
|
+
assignee == '-1' ? 'default user' : "'#{assignee}'"
|
54
|
+
end
|
55
|
+
|
56
|
+
def assignee
|
57
|
+
@assignee ||= (
|
58
|
+
assignee = options['assignee'] || io.ask('Assignee?', default: 'auto')
|
59
|
+
assignee == 'auto' ? '-1' : assignee
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Jira
|
2
|
+
class CLI < Thor
|
3
|
+
|
4
|
+
desc "attachments", "View ticket attachments"
|
5
|
+
def attachments(ticket=Jira::Core.ticket)
|
6
|
+
Command::Attachments.new(ticket).run
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module Command
|
12
|
+
class Attachments < Base
|
13
|
+
|
14
|
+
attr_accessor :ticket
|
15
|
+
|
16
|
+
def initialize(ticket)
|
17
|
+
self.ticket = ticket
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
return if ticket.empty?
|
22
|
+
return if metadata.empty?
|
23
|
+
return if metadata['fields'].nil?
|
24
|
+
|
25
|
+
attachments=metadata['fields']['attachment']
|
26
|
+
if !attachments.nil? and attachments.count > 0
|
27
|
+
attachments.each do |attachment|
|
28
|
+
name=attachment['filename']
|
29
|
+
url=attachment['content']
|
30
|
+
|
31
|
+
puts "#{Jira::Format.user(name)} #{url}"
|
32
|
+
end
|
33
|
+
else
|
34
|
+
puts "No attachments found for ticket #{ticket}."
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def metadata
|
41
|
+
@metadata ||= api.get("issue/#{ticket}")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Jira
|
2
|
+
class CLI < Thor
|
3
|
+
|
4
|
+
desc "checkout <ticket>", "Checks out a ticket from JIRA in the git branch"
|
5
|
+
method_option :remote, aliases: "-r", type: :string, default: nil, lazy_default: "", banner: "REMOTE"
|
6
|
+
def checkout(ticket)
|
7
|
+
Command::Checkout.new(ticket, options).run
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
module Command
|
13
|
+
class Checkout < 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 unless Jira::Core.ticket?(ticket)
|
24
|
+
return if metadata.empty?
|
25
|
+
unless metadata['errorMessages'].nil?
|
26
|
+
on_failure
|
27
|
+
return
|
28
|
+
end
|
29
|
+
unless remote?
|
30
|
+
on_failure
|
31
|
+
return
|
32
|
+
end
|
33
|
+
|
34
|
+
create_branch unless branches.include?(ticket)
|
35
|
+
checkout_branch
|
36
|
+
reset_branch unless branches.include?(ticket)
|
37
|
+
on_success
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def on_success
|
43
|
+
puts "Ticket #{ticket} checked out."
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_failure
|
47
|
+
puts "No ticket checked out."
|
48
|
+
end
|
49
|
+
|
50
|
+
def branches
|
51
|
+
@branches ||= `git branch --list 2> /dev/null`.split(' ')
|
52
|
+
@branches.delete("*")
|
53
|
+
@branches
|
54
|
+
end
|
55
|
+
|
56
|
+
def create_branch
|
57
|
+
`git branch #{ticket} 2> /dev/null`
|
58
|
+
end
|
59
|
+
|
60
|
+
def checkout_branch
|
61
|
+
`git checkout #{ticket} 2> /dev/null`
|
62
|
+
end
|
63
|
+
|
64
|
+
def metadata
|
65
|
+
@metadata ||= api.get("issue/#{ticket}")
|
66
|
+
end
|
67
|
+
|
68
|
+
def remote
|
69
|
+
@remote ||= options['remote'] || io.select('Remote?', remotes)
|
70
|
+
end
|
71
|
+
|
72
|
+
def remotes
|
73
|
+
@remotes ||= `git remote 2> /dev/null`.split(' ')
|
74
|
+
end
|
75
|
+
|
76
|
+
def remote?
|
77
|
+
return true if remotes.include?(remote)
|
78
|
+
false
|
79
|
+
end
|
80
|
+
|
81
|
+
def reset_branch
|
82
|
+
`git reset --hard #{remote} 2> /dev/null`
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Jira
|
2
|
+
class Comment < Thor
|
3
|
+
|
4
|
+
desc 'add', 'Add a comment to the input ticket'
|
5
|
+
method_option :text, aliases: "-t", type: :string, default: nil, lazy_default: "", banner: "TEXT"
|
6
|
+
def add(ticket=Jira::Core.ticket)
|
7
|
+
Command::Comment::Add.new(ticket, options).run
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
module Command
|
13
|
+
module Comment
|
14
|
+
class Add < 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 text.empty?
|
25
|
+
api.post "issue/#{ticket}/comment",
|
26
|
+
params: params,
|
27
|
+
success: on_success,
|
28
|
+
failure: on_failure
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def params
|
34
|
+
{ body: text }
|
35
|
+
end
|
36
|
+
|
37
|
+
def text
|
38
|
+
body(options['text'])
|
39
|
+
end
|
40
|
+
|
41
|
+
def on_success
|
42
|
+
->{ puts "Successfully posted your comment." }
|
43
|
+
end
|
44
|
+
|
45
|
+
def on_failure
|
46
|
+
->{ puts "No comment posted." }
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Jira
|
2
|
+
class Comment < Thor
|
3
|
+
|
4
|
+
desc 'delete', 'Delete a comment to the input ticket'
|
5
|
+
def delete(ticket=Jira::Core.ticket)
|
6
|
+
Command::Comment::Delete.new(ticket).run
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module Command
|
12
|
+
module Comment
|
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 unless comments?
|
23
|
+
api.delete endpoint,
|
24
|
+
success: on_success,
|
25
|
+
failure: on_failure
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def comments?
|
31
|
+
if json.empty?
|
32
|
+
puts "Ticket #{ticket} has no comments."
|
33
|
+
return false
|
34
|
+
end
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
def endpoint
|
39
|
+
"issue/#{ticket}/comment/#{to_delete['id']}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_success
|
43
|
+
->{ puts "Successfully deleted comment from #{to_delete['updateAuthor']['displayName']}" }
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_failure
|
47
|
+
->{ puts "No comment deleted." }
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_delete
|
51
|
+
@to_delete ||= comments[
|
52
|
+
io.select("Select a comment to delete:", comments.keys)
|
53
|
+
]
|
54
|
+
end
|
55
|
+
|
56
|
+
def comments
|
57
|
+
@comments ||= (
|
58
|
+
comments = {}
|
59
|
+
json.each do |comment|
|
60
|
+
comments[description_for(comment)] = comment
|
61
|
+
end
|
62
|
+
comments
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def description_for(comment)
|
67
|
+
author = comment['updateAuthor']['displayName']
|
68
|
+
updated_at = Jira::Format.time(Time.parse(comment['updated']))
|
69
|
+
body = comment['body'].split.join(" ")
|
70
|
+
truncate("#{author} @ #{updated_at}: #{body}", 160)
|
71
|
+
end
|
72
|
+
|
73
|
+
def json
|
74
|
+
@json ||= api.get("issue/#{ticket}/comment")['comments'] || {}
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Jira
|
2
|
+
class Comment < Thor
|
3
|
+
|
4
|
+
desc 'list', 'Lists the comments of the input ticket'
|
5
|
+
def list(ticket=Jira::Core.ticket)
|
6
|
+
Command::Comment::List.new(ticket).run
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module Command
|
12
|
+
module Comment
|
13
|
+
class List < Base
|
14
|
+
|
15
|
+
attr_accessor :ticket
|
16
|
+
|
17
|
+
def initialize(ticket)
|
18
|
+
self.ticket = ticket
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
return if comments.nil?
|
23
|
+
|
24
|
+
if comments.empty?
|
25
|
+
puts "Ticket #{ticket} has no comments."
|
26
|
+
return
|
27
|
+
end
|
28
|
+
render_table(header, rows)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_accessor :comment
|
34
|
+
|
35
|
+
def header
|
36
|
+
[ 'Author', 'Updated At', 'Body' ]
|
37
|
+
end
|
38
|
+
|
39
|
+
def rows
|
40
|
+
rows = []
|
41
|
+
comments.each do |comment|
|
42
|
+
self.comment = comment
|
43
|
+
rows << row
|
44
|
+
end
|
45
|
+
rows
|
46
|
+
end
|
47
|
+
|
48
|
+
def row
|
49
|
+
[ author, updated_at, body ]
|
50
|
+
end
|
51
|
+
|
52
|
+
def author
|
53
|
+
comment['updateAuthor']['displayName']
|
54
|
+
end
|
55
|
+
|
56
|
+
def updated_at
|
57
|
+
Jira::Format.time(Time.parse(comment['updated']))
|
58
|
+
end
|
59
|
+
|
60
|
+
def body
|
61
|
+
body = comment['body'].gsub("\r\n|\r|\n", ";")
|
62
|
+
truncate(body, 45)
|
63
|
+
end
|
64
|
+
|
65
|
+
def comments
|
66
|
+
@comments ||= api.get("issue/#{ticket}/comment")['comments']
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|