jira-cli 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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