jira-cli 0.2.2 → 0.3.0
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 +4 -4
- data/README.md +18 -28
- data/bin/jira +3 -1
- data/lib/jira.rb +12 -6
- data/lib/jira/api.rb +10 -5
- data/lib/jira/auth_api.rb +11 -0
- data/lib/jira/command.rb +21 -1
- data/lib/jira/commands/all.rb +2 -2
- data/lib/jira/commands/assign.rb +2 -2
- data/lib/jira/commands/comment.rb +8 -98
- data/lib/jira/commands/comment/add.rb +46 -0
- data/lib/jira/commands/comment/delete.rb +80 -0
- data/lib/jira/commands/comment/list.rb +69 -0
- data/lib/jira/commands/comment/update.rb +88 -0
- data/lib/jira/commands/delete.rb +0 -2
- data/lib/jira/commands/describe.rb +0 -2
- data/lib/jira/commands/install.rb +39 -17
- data/lib/jira/commands/link.rb +4 -3
- data/lib/jira/commands/log.rb +7 -72
- data/lib/jira/commands/log/add.rb +50 -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/new.rb +4 -6
- data/lib/jira/commands/rename.rb +0 -2
- data/lib/jira/commands/sprint.rb +3 -3
- data/lib/jira/commands/tickets.rb +0 -2
- data/lib/jira/commands/transition.rb +0 -2
- data/lib/jira/commands/vote.rb +5 -107
- 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/watch.rb +5 -108
- 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/constants.rb +1 -1
- data/lib/jira/core.rb +9 -1
- data/lib/jira/sprint_api.rb +2 -18
- metadata +17 -5
- data/lib/jira/commands/commit.rb +0 -14
- data/lib/jira/legacy_api.rb +0 -102
- data/lib/jira/mixins.rb +0 -56
@@ -0,0 +1,69 @@
|
|
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
|
+
if comments.empty?
|
23
|
+
puts "Ticket #{ticket} has no comments."
|
24
|
+
return
|
25
|
+
end
|
26
|
+
render_table(header, rows)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_accessor :comment
|
32
|
+
|
33
|
+
def header
|
34
|
+
[ 'Author', 'Updated At', 'Body' ]
|
35
|
+
end
|
36
|
+
|
37
|
+
def rows
|
38
|
+
rows = []
|
39
|
+
comments.each do |comment|
|
40
|
+
self.comment = comment
|
41
|
+
rows << row
|
42
|
+
end
|
43
|
+
rows
|
44
|
+
end
|
45
|
+
|
46
|
+
def row
|
47
|
+
[ author, updated_at, body ]
|
48
|
+
end
|
49
|
+
|
50
|
+
def author
|
51
|
+
comment['updateAuthor']['displayName']
|
52
|
+
end
|
53
|
+
|
54
|
+
def updated_at
|
55
|
+
Jira::Format.time(Time.parse(comment['updated']))
|
56
|
+
end
|
57
|
+
|
58
|
+
def body
|
59
|
+
comment['body']
|
60
|
+
end
|
61
|
+
|
62
|
+
def comments
|
63
|
+
@comments ||= api.get("issue/#{ticket}/comment")['comments']
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Jira
|
2
|
+
class Comment < Thor
|
3
|
+
|
4
|
+
desc 'update', 'Update a comment to the input ticket'
|
5
|
+
def update(ticket=Jira::Core.ticket)
|
6
|
+
Command::Comment::Update.new(ticket).run
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module Command
|
12
|
+
module Comment
|
13
|
+
class Update < 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.patch endpoint,
|
24
|
+
params: params,
|
25
|
+
success: on_success,
|
26
|
+
failure: on_failure
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def params
|
32
|
+
{ body: body }
|
33
|
+
end
|
34
|
+
|
35
|
+
def comments?
|
36
|
+
if json.empty?
|
37
|
+
puts "Ticket #{ticket} has no comments."
|
38
|
+
return false
|
39
|
+
end
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
43
|
+
def endpoint
|
44
|
+
"issue/#{ticket}/comment/#{to_update['id']}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def on_success
|
48
|
+
->{
|
49
|
+
puts "Successfully updated comment originally from"\
|
50
|
+
" #{to_update['updateAuthor']['displayName']}."
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_failure
|
55
|
+
->{ puts "No comment updated." }
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_update
|
59
|
+
@to_update ||= comments[
|
60
|
+
io.select("Select a comment to update:", comments.keys)
|
61
|
+
]
|
62
|
+
end
|
63
|
+
|
64
|
+
def comments
|
65
|
+
@comments ||= (
|
66
|
+
comments = {}
|
67
|
+
json.each do |comment|
|
68
|
+
comments[description_for(comment)] = comment
|
69
|
+
end
|
70
|
+
comments
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
def description_for(comment)
|
75
|
+
author = comment['updateAuthor']['displayName']
|
76
|
+
updated_at = Jira::Format.time(Time.parse(comment['updated']))
|
77
|
+
body = comment['body'].gsub("\r\n|\r|\n", ";")
|
78
|
+
truncate("#{author} @ #{updated_at}: #{body}", 160)
|
79
|
+
end
|
80
|
+
|
81
|
+
def json
|
82
|
+
@json ||= api.get("issue/#{ticket}/comment")['comments']
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/jira/commands/delete.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require_relative '../command'
|
2
|
-
|
3
1
|
module Jira
|
4
2
|
class CLI < Thor
|
5
3
|
|
@@ -15,35 +13,53 @@ module Jira
|
|
15
13
|
|
16
14
|
def run
|
17
15
|
io.say('Please enter your JIRA information.')
|
18
|
-
inifile[:global] =
|
16
|
+
inifile[:global] = base_params
|
17
|
+
inifile.write # Do this now because cookie authentication uses api calls
|
18
|
+
|
19
|
+
inifile.delete_section("cookie") if inifile.has_section?("cookie")
|
20
|
+
case authentication
|
21
|
+
when "basic"
|
22
|
+
inifile[:global][:password] = password
|
23
|
+
when "token"
|
24
|
+
inifile[:global][:token] = token
|
25
|
+
when "cookie"
|
26
|
+
response = cookie
|
27
|
+
inifile[:cookie] = {}
|
28
|
+
inifile[:cookie][:name] = response['name']
|
29
|
+
inifile[:cookie][:value] = response['value']
|
30
|
+
end
|
19
31
|
inifile.write
|
20
32
|
end
|
21
33
|
|
22
34
|
private
|
23
35
|
|
24
|
-
def
|
25
|
-
|
36
|
+
def base_params
|
37
|
+
{
|
26
38
|
url: url,
|
27
39
|
username: username,
|
28
40
|
}
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
41
|
+
end
|
42
|
+
|
43
|
+
def session_params
|
44
|
+
{
|
45
|
+
username: username,
|
46
|
+
password: password
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def authentication
|
51
|
+
@authentication ||= io.select(
|
52
|
+
"Select an authentication type:",
|
53
|
+
["basic", "cookie", "token"]
|
54
|
+
)
|
39
55
|
end
|
40
56
|
|
41
57
|
def url
|
42
|
-
io.ask("JIRA URL:")
|
58
|
+
@url ||= io.ask("JIRA URL:")
|
43
59
|
end
|
44
60
|
|
45
61
|
def username
|
46
|
-
io.ask("JIRA username:")
|
62
|
+
@username ||= io.ask("JIRA username:")
|
47
63
|
end
|
48
64
|
|
49
65
|
def password
|
@@ -54,6 +70,12 @@ module Jira
|
|
54
70
|
io.ask("JIRA token:")
|
55
71
|
end
|
56
72
|
|
73
|
+
def cookie
|
74
|
+
response = auth_api.post('session', params: session_params)
|
75
|
+
return {} unless response['errorMessages'].nil?
|
76
|
+
response['session']
|
77
|
+
end
|
78
|
+
|
57
79
|
def inifile
|
58
80
|
@inifile ||= IniFile.new(
|
59
81
|
comment: '#',
|
data/lib/jira/commands/link.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require_relative '../command'
|
2
|
-
|
3
1
|
module Jira
|
4
2
|
class CLI < Thor
|
5
3
|
|
@@ -69,7 +67,10 @@ module Jira
|
|
69
67
|
end
|
70
68
|
|
71
69
|
def on_success
|
72
|
-
->{
|
70
|
+
->{
|
71
|
+
puts "Successfully linked ticket #{ticket} to"\
|
72
|
+
" ticket #{outward_ticket}."
|
73
|
+
}
|
73
74
|
end
|
74
75
|
|
75
76
|
def on_failure
|
data/lib/jira/commands/log.rb
CHANGED
@@ -1,78 +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
|
+
|
1
6
|
module Jira
|
2
7
|
class CLI < Thor
|
3
8
|
|
4
|
-
desc
|
5
|
-
|
6
|
-
time_spent = self.io.ask("Time spent on ticket #{ticket}:")
|
7
|
-
self.api.post("issue/#{ticket}/worklog", { timeSpent: time_spent }) do |json|
|
8
|
-
puts "Successfully logged #{time_spent} on ticket #{ticket}."
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
desc "logd", "Deletes work against the input ticket"
|
13
|
-
def logd(ticket=Jira::Core.ticket)
|
14
|
-
logs(ticket) if self.io.yes?("List worklogs for ticket #{ticket}?")
|
15
|
-
|
16
|
-
index = self.get_type_of_index("worklog", "delete")
|
17
|
-
puts "No worklog deleted." and return if index < 0
|
18
|
-
|
19
|
-
self.api.get("issue/#{ticket}/worklog") do |json|
|
20
|
-
worklogs = json['worklogs']
|
21
|
-
if index < worklogs.count
|
22
|
-
id = worklogs[index]['id']
|
23
|
-
time_spent = worklogs[index]['timeSpent']
|
24
|
-
self.api.delete("issue/#{ticket}/worklog/#{id}") do |json|
|
25
|
-
puts "Successfully deleted #{time_spent} on ticket #{ticket}"
|
26
|
-
return
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
puts "No worklog deleted."
|
31
|
-
end
|
32
|
-
|
33
|
-
desc "logs", "Lists work against the input ticket"
|
34
|
-
def logs(ticket=Jira::Core.ticket)
|
35
|
-
self.api.get("issue/#{ticket}/worklog") do |json|
|
36
|
-
worklogs = json['worklogs']
|
37
|
-
if worklogs.count > 0
|
38
|
-
worklogs.each do |worklog|
|
39
|
-
author = worklog['author']['displayName']
|
40
|
-
time = Time.parse(worklog['updated'])
|
41
|
-
time_spent = worklog['timeSpent']
|
42
|
-
|
43
|
-
printf "[%2d]", worklogs.index(worklog)
|
44
|
-
puts " #{Jira::Format.user(author)} @ "\
|
45
|
-
"#{Jira::Format.time(time)}:\n"\
|
46
|
-
"#{Jira::Format.comment(time_spent)}"
|
47
|
-
end
|
48
|
-
else
|
49
|
-
puts "There are no worklogs on ticket #{ticket}"
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
desc "logu", "Updates work against the input ticket"
|
55
|
-
def logu(ticket=Jira::Core.ticket)
|
56
|
-
logs(ticket) if self.io.yes?("List worklogs for ticket #{ticket}?")
|
57
|
-
|
58
|
-
index = self.get_type_of_index("worklog", "update")
|
59
|
-
puts "No worklog updated." and return if index < 0
|
60
|
-
|
61
|
-
time_spent = self.io.ask("Time spent on #{ticket}:").strip
|
62
|
-
puts "No worklog updated." and return if time_spent.empty?
|
63
|
-
|
64
|
-
self.api.get("issue/#{ticket}/worklog") do |json|
|
65
|
-
worklogs = json['worklogs']
|
66
|
-
if index < worklogs.count
|
67
|
-
id = worklogs[index]['id']
|
68
|
-
self.api.put("issue/#{ticket}/worklog/#{id}", { timeSpent: time_spent }) do |json|
|
69
|
-
puts "Successfully updated #{time_spent} on ticket #{ticket}."
|
70
|
-
return
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
puts "No worklog updated."
|
75
|
-
end
|
9
|
+
desc 'log <command>', 'Commands for logging operations in JIRA'
|
10
|
+
subcommand 'log', Log
|
76
11
|
|
77
12
|
end
|
78
13
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Jira
|
2
|
+
class Log < Thor
|
3
|
+
|
4
|
+
desc 'add', 'Logs work against the input ticket'
|
5
|
+
def add(ticket=Jira::Core.ticket)
|
6
|
+
Command::Log::Add.new(ticket).run
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module Command
|
12
|
+
module Log
|
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 time_spent.empty?
|
23
|
+
api.post "issue/#{ticket}/worklog",
|
24
|
+
params: params,
|
25
|
+
success: on_success,
|
26
|
+
failure: on_failure
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def params
|
32
|
+
{ timeSpent: time_spent }
|
33
|
+
end
|
34
|
+
|
35
|
+
def time_spent
|
36
|
+
@time_spent ||= io.ask("Time spent on ticket #{ticket}:")
|
37
|
+
end
|
38
|
+
|
39
|
+
def on_success
|
40
|
+
->{ puts "Successfully logged #{time_spent} on ticket #{ticket}." }
|
41
|
+
end
|
42
|
+
|
43
|
+
def on_failure
|
44
|
+
->{ puts "No work was logged on ticket #{ticket}." }
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Jira
|
2
|
+
class Log < Thor
|
3
|
+
|
4
|
+
desc 'delete', 'Deletes logged work against the input ticket'
|
5
|
+
def delete(ticket=Jira::Core.ticket)
|
6
|
+
Command::Log::Delete.new(ticket).run
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module Command
|
12
|
+
module Log
|
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 logs?
|
23
|
+
api.delete endpoint,
|
24
|
+
success: on_success,
|
25
|
+
failure: on_failure
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def logs?
|
31
|
+
if json.empty?
|
32
|
+
puts "Ticket #{ticket} has no work logged."
|
33
|
+
return false
|
34
|
+
end
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
def endpoint
|
39
|
+
"issue/#{ticket}/worklog/#{to_delete['id']}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_success
|
43
|
+
->{ puts "Successfully deleted #{to_delete['timeSpent']}." }
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_failure
|
47
|
+
->{ puts "No logged work deleted." }
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_delete
|
51
|
+
@to_delete ||= logs[
|
52
|
+
io.select("Select a worklog to delete:", logs.keys)
|
53
|
+
]
|
54
|
+
end
|
55
|
+
|
56
|
+
def logs
|
57
|
+
@logs ||= (
|
58
|
+
logs = {}
|
59
|
+
json.each do |log|
|
60
|
+
logs[description_for(log)] = log
|
61
|
+
end
|
62
|
+
logs
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def description_for(log)
|
67
|
+
author = log['updateAuthor']['displayName']
|
68
|
+
updated_at = Jira::Format.time(Time.parse(log['updated']))
|
69
|
+
time_spent = log['timeSpent']
|
70
|
+
"#{author} @ #{updated_at}: #{time_spent}"
|
71
|
+
end
|
72
|
+
|
73
|
+
def json
|
74
|
+
@json ||= api.get("issue/#{ticket}/worklog")['worklogs']
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|