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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -28
  3. data/bin/jira +3 -1
  4. data/lib/jira.rb +12 -6
  5. data/lib/jira/api.rb +10 -5
  6. data/lib/jira/auth_api.rb +11 -0
  7. data/lib/jira/command.rb +21 -1
  8. data/lib/jira/commands/all.rb +2 -2
  9. data/lib/jira/commands/assign.rb +2 -2
  10. data/lib/jira/commands/comment.rb +8 -98
  11. data/lib/jira/commands/comment/add.rb +46 -0
  12. data/lib/jira/commands/comment/delete.rb +80 -0
  13. data/lib/jira/commands/comment/list.rb +69 -0
  14. data/lib/jira/commands/comment/update.rb +88 -0
  15. data/lib/jira/commands/delete.rb +0 -2
  16. data/lib/jira/commands/describe.rb +0 -2
  17. data/lib/jira/commands/install.rb +39 -17
  18. data/lib/jira/commands/link.rb +4 -3
  19. data/lib/jira/commands/log.rb +7 -72
  20. data/lib/jira/commands/log/add.rb +50 -0
  21. data/lib/jira/commands/log/delete.rb +80 -0
  22. data/lib/jira/commands/log/list.rb +69 -0
  23. data/lib/jira/commands/log/update.rb +89 -0
  24. data/lib/jira/commands/new.rb +4 -6
  25. data/lib/jira/commands/rename.rb +0 -2
  26. data/lib/jira/commands/sprint.rb +3 -3
  27. data/lib/jira/commands/tickets.rb +0 -2
  28. data/lib/jira/commands/transition.rb +0 -2
  29. data/lib/jira/commands/vote.rb +5 -107
  30. data/lib/jira/commands/vote/add.rb +43 -0
  31. data/lib/jira/commands/vote/delete.rb +46 -0
  32. data/lib/jira/commands/vote/list.rb +59 -0
  33. data/lib/jira/commands/watch.rb +5 -108
  34. data/lib/jira/commands/watch/add.rb +43 -0
  35. data/lib/jira/commands/watch/delete.rb +46 -0
  36. data/lib/jira/commands/watch/list.rb +59 -0
  37. data/lib/jira/constants.rb +1 -1
  38. data/lib/jira/core.rb +9 -1
  39. data/lib/jira/sprint_api.rb +2 -18
  40. metadata +17 -5
  41. data/lib/jira/commands/commit.rb +0 -14
  42. data/lib/jira/legacy_api.rb +0 -102
  43. 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
@@ -1,5 +1,3 @@
1
- require_relative '../command'
2
-
3
1
  module Jira
4
2
  class CLI < Thor
5
3
 
@@ -1,5 +1,3 @@
1
- require_relative '../command'
2
-
3
1
  module Jira
4
2
  class CLI < Thor
5
3
 
@@ -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] = params
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 params
25
- args = {
36
+ def base_params
37
+ {
26
38
  url: url,
27
39
  username: username,
28
40
  }
29
- response = io.select("Select an authentication type:", ["basic", "token"])
30
- case response
31
- when "basic"
32
- args[:password] = password
33
- when "token"
34
- args[:token] = token
35
- else
36
- raise InstallationException
37
- end
38
- args
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: '#',
@@ -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
- ->{ puts "Successfully linked ticket #{ticket} to ticket #{outward_ticket}." }
70
+ ->{
71
+ puts "Successfully linked ticket #{ticket} to"\
72
+ " ticket #{outward_ticket}."
73
+ }
73
74
  end
74
75
 
75
76
  def on_failure
@@ -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 "log", "Logs work against the input ticket"
5
- def log(ticket=Jira::Core.ticket)
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