jira-cli 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/jira.rb +1 -1
- data/lib/jira/api.rb +51 -24
- data/lib/jira/commands/comment.rb +2 -8
- data/lib/jira/commands/describe.rb +9 -8
- data/lib/jira/commands/log.rb +1 -4
- data/lib/jira/commands/new.rb +111 -0
- data/lib/jira/commands/rename.rb +19 -0
- data/lib/jira/commands/transition.rb +21 -26
- data/lib/jira/constants.rb +1 -1
- data/lib/jira/mixins.rb +8 -3
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cde1ac20a643d00b9b6d3308c49a84b94db85281
|
4
|
+
data.tar.gz: 807d024db48e5b22661a588aa6290c2ba65c3cfc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1c9306b45a7f7126bafda539d153d6d20fecff6dd566b7c21007ab8b33f5ec2a3aa2f7f9e1ca80c830c22ae8e4a31c7a72b0afd91378c31da9feeaaba4e401a
|
7
|
+
data.tar.gz: 9d0cda918e9e06385c4ae62c5872a506c7c80104a4f250507ef4a1efc143623de42ae4f152d600e4a70836104437b5021cb068701ea3d1b290b259ad3aebd0fd
|
data/lib/jira.rb
CHANGED
data/lib/jira/api.rb
CHANGED
@@ -7,35 +7,62 @@ module Jira
|
|
7
7
|
def initialize
|
8
8
|
@client = Faraday.new
|
9
9
|
@client.basic_auth(Jira::Core.username, Jira::Core.password)
|
10
|
-
end
|
11
10
|
|
12
|
-
|
13
|
-
# Issue an API GET request and return parsed JSON
|
14
|
-
#
|
15
|
-
# @param path [String] API path
|
16
|
-
#
|
17
|
-
# @return [JSON] parsed API response
|
18
|
-
#
|
19
|
-
def get(path, params={})
|
20
|
-
response = @client.get(self.endpoint(path), params, self.headers)
|
21
|
-
return response.body.to_s.from_json
|
22
|
-
end
|
23
|
-
|
24
|
-
#
|
25
|
-
# Issue an API POST request and return parsed JSON
|
26
|
-
#
|
27
|
-
# @param path [String] API path
|
28
|
-
# @param params [Hash] params to post
|
29
|
-
#
|
30
|
-
# @return [JSON] parsed API response
|
31
|
-
#
|
32
|
-
def post(path, params={})
|
33
|
-
response = @client.post(self.endpoint(path), params, self.headers)
|
34
|
-
return response.body.to_s.from_json
|
11
|
+
self.define_actions
|
35
12
|
end
|
36
13
|
|
37
14
|
protected
|
38
15
|
|
16
|
+
#
|
17
|
+
# Defines the API GET, POST, PUT interaction methods
|
18
|
+
#
|
19
|
+
def define_actions
|
20
|
+
#
|
21
|
+
# def method(path, params={})
|
22
|
+
#
|
23
|
+
# Issue an API GET, POST, or PUT request and return parse JSON
|
24
|
+
#
|
25
|
+
# @param path [String] API path
|
26
|
+
# @param params [Hash] params to send
|
27
|
+
#
|
28
|
+
# @yield(Hash) yields to a success block
|
29
|
+
#
|
30
|
+
# @return [JSON] parased API response
|
31
|
+
#
|
32
|
+
[:get, :post, :put].each do |method|
|
33
|
+
self.class.send(:define_method, method) do |path, params=nil, verbose=true, &block|
|
34
|
+
params = params.to_json if !params.nil?
|
35
|
+
response = @client.send(
|
36
|
+
method,
|
37
|
+
self.endpoint(path),
|
38
|
+
params,
|
39
|
+
self.headers
|
40
|
+
)
|
41
|
+
json = response.body.to_s.from_json
|
42
|
+
if self.errorless?(json, verbose)
|
43
|
+
block.call(json)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# If any, outputs all API errors described by the input JSON
|
51
|
+
#
|
52
|
+
# @param json [Hash] API response JSON
|
53
|
+
# @param verbose [Boolean] true if errors should be output
|
54
|
+
#
|
55
|
+
# @return [Boolean] true if no errors exist
|
56
|
+
#
|
57
|
+
def errorless?(json, verbose=true)
|
58
|
+
errors = json['errorMessages']
|
59
|
+
if !errors.nil?
|
60
|
+
puts errors.join('. ') if verbose
|
61
|
+
return false
|
62
|
+
end
|
63
|
+
return true
|
64
|
+
end
|
65
|
+
|
39
66
|
#
|
40
67
|
# Returns the full JIRA REST API endpoint
|
41
68
|
#
|
@@ -7,19 +7,15 @@ module Jira
|
|
7
7
|
if comment.strip.empty?
|
8
8
|
puts "No comment posted."
|
9
9
|
else
|
10
|
-
|
11
|
-
if json['errorMessages'].nil?
|
10
|
+
self.api.post("issue/#{ticket}/comment", { body: comment }) do |json|
|
12
11
|
puts "Successfully posted your comment."
|
13
|
-
else
|
14
|
-
puts json['errorMessages'].join('. ')
|
15
12
|
end
|
16
13
|
end
|
17
14
|
end
|
18
15
|
|
19
16
|
desc "comments", "Lists the comments of the input ticket"
|
20
17
|
def comments(ticket=Jira::Core.ticket)
|
21
|
-
|
22
|
-
if json['errorMessages'].nil?
|
18
|
+
self.api.get("issue/#{ticket}") do |json|
|
23
19
|
comments = json['fields']['comment']['comments']
|
24
20
|
if comments.count > 0
|
25
21
|
comments.each do |comment|
|
@@ -34,8 +30,6 @@ module Jira
|
|
34
30
|
else
|
35
31
|
puts "There are no comments on issue #{ticket}."
|
36
32
|
end
|
37
|
-
else
|
38
|
-
puts json['errorMessages'].join('. ')
|
39
33
|
end
|
40
34
|
end
|
41
35
|
|
@@ -3,7 +3,12 @@ module Jira
|
|
3
3
|
|
4
4
|
desc "describe", "Describes the input ticket"
|
5
5
|
def describe(ticket=Jira::Core.ticket)
|
6
|
-
|
6
|
+
if Jira::Core.ticket?(ticket)
|
7
|
+
output = description(ticket.strip, false, true)
|
8
|
+
puts output if !output.strip.empty?
|
9
|
+
else
|
10
|
+
puts "The ticket #{ticket} is not a valid JIRA ticket."
|
11
|
+
end
|
7
12
|
end
|
8
13
|
|
9
14
|
desc "all", "Describes all local branches that match JIRA ticketing syntax"
|
@@ -30,7 +35,7 @@ module Jira
|
|
30
35
|
# asynchronously fetch and describe tickets
|
31
36
|
output = ""
|
32
37
|
threads = []
|
33
|
-
if
|
38
|
+
if !tickets[:current].nil?
|
34
39
|
threads << Thread.new{ puts description(tickets[:current], true) }
|
35
40
|
end
|
36
41
|
mutex = Mutex.new
|
@@ -57,8 +62,7 @@ module Jira
|
|
57
62
|
# @return [String] formatted summary string
|
58
63
|
#
|
59
64
|
def description(ticket, star=false, verbose=false)
|
60
|
-
|
61
|
-
if json['errorMessages'].nil?
|
65
|
+
self.api.get("issue/#{ticket}", nil, verbose) do |json|
|
62
66
|
summary = json['fields']['summary']
|
63
67
|
status = json['fields']['status']['name']
|
64
68
|
assignee = json['fields']['assignee']['name']
|
@@ -67,11 +71,8 @@ module Jira
|
|
67
71
|
("(" + Jira::Format.user(assignee) + ")").ljust(20) +
|
68
72
|
Jira::Format.status(status).ljust(26) +
|
69
73
|
Jira::Format.summary(summary)
|
70
|
-
elsif verbose
|
71
|
-
return json['errorMessages'].join('. ')
|
72
|
-
else
|
73
|
-
return ""
|
74
74
|
end
|
75
|
+
return ""
|
75
76
|
end
|
76
77
|
|
77
78
|
end
|
data/lib/jira/commands/log.rb
CHANGED
@@ -4,11 +4,8 @@ module Jira
|
|
4
4
|
desc "log", "Logs work against the input ticket"
|
5
5
|
def log(ticket=Jira::Core.ticket)
|
6
6
|
time_spent = self.cli.ask("Time spent on #{ticket}: ")
|
7
|
-
|
8
|
-
if json['errorMessages'].nil?
|
7
|
+
self.api.post("issue/#{ticket}/worklog", { timeSpent: time_spent }) do |json|
|
9
8
|
puts "Successfully logged #{time_spent} on #{ticket}."
|
10
|
-
else
|
11
|
-
puts json['errorMessages'].join('. ')
|
12
9
|
end
|
13
10
|
end
|
14
11
|
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Jira
|
2
|
+
class CLI < Thor
|
3
|
+
|
4
|
+
desc "new", "Creates a new ticket in JIRA and checks out the git branch"
|
5
|
+
def new
|
6
|
+
self.api.get("issue/createmeta") do |meta|
|
7
|
+
# determine project
|
8
|
+
project = self.select_project(meta)
|
9
|
+
break if project.empty?
|
10
|
+
|
11
|
+
# determine issue type
|
12
|
+
issue_type = self.select_issue_type(project)
|
13
|
+
return if issue_type.empty?
|
14
|
+
|
15
|
+
# determine summary and description
|
16
|
+
summary = self.cli.ask("\nSummary: ")
|
17
|
+
description = self.cli.ask("Description:")
|
18
|
+
|
19
|
+
# determine api parameters
|
20
|
+
params = {
|
21
|
+
fields: {
|
22
|
+
project: { id: project[:id] },
|
23
|
+
issuetype: { id: issue_type },
|
24
|
+
summary: summary,
|
25
|
+
description: description
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
# post issue to server
|
30
|
+
self.api.post("issue", params) do |json|
|
31
|
+
ticket = json['key']
|
32
|
+
`git checkout -b #{ticket} 2> /dev/null`
|
33
|
+
puts "\nTicket and branch #{Jira::Format.ticket(ticket)} created."
|
34
|
+
return
|
35
|
+
end
|
36
|
+
end
|
37
|
+
puts "No ticket created."
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
#
|
43
|
+
# Given the creation metadata, prompts the user for the project to use,
|
44
|
+
# then return the project data hash
|
45
|
+
#
|
46
|
+
# @param json [Hash] creation metadata
|
47
|
+
#
|
48
|
+
# @return [Hash] selected project's metadata
|
49
|
+
#
|
50
|
+
def select_project(json)
|
51
|
+
projects = {}
|
52
|
+
json['projects'].each do |project|
|
53
|
+
data = {
|
54
|
+
id: project['id'],
|
55
|
+
issues: project['issuetypes']
|
56
|
+
}
|
57
|
+
projects[project['name']] = data
|
58
|
+
end
|
59
|
+
projects['Cancel'] = nil
|
60
|
+
|
61
|
+
self.cli.choose do |menu|
|
62
|
+
menu.index = :number
|
63
|
+
menu.index_suffix = ") "
|
64
|
+
menu.header = "Select a project to create issue under"
|
65
|
+
menu.prompt = "Project: "
|
66
|
+
projects.keys.each do |choice|
|
67
|
+
menu.choice choice do
|
68
|
+
project_data = projects[choice]
|
69
|
+
if !project_data.nil?
|
70
|
+
return project_data
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
return {}
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Given the project metadata, prompts the user for the issue type to use
|
80
|
+
# and returns the selected issue type.
|
81
|
+
#
|
82
|
+
# @param project_data [Hash] project metadata
|
83
|
+
#
|
84
|
+
# @return [String] selected issue type
|
85
|
+
#
|
86
|
+
def select_issue_type(project_data)
|
87
|
+
issue_types = {}
|
88
|
+
project_data[:issues].each do |issue_type|
|
89
|
+
issue_types[issue_type['name']] = issue_type['id']
|
90
|
+
end
|
91
|
+
issue_types['Cancel'] = nil
|
92
|
+
|
93
|
+
self.cli.choose do |menu|
|
94
|
+
menu.index = :number
|
95
|
+
menu.index_suffix = ") "
|
96
|
+
menu.header = "\nSelect an issue type"
|
97
|
+
menu.prompt = "Issue type: "
|
98
|
+
issue_types.keys.each do |choice|
|
99
|
+
menu.choice choice do
|
100
|
+
issue_type_id = issue_types[choice]
|
101
|
+
if !issue_type_id.nil?
|
102
|
+
return issue_type_id
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
return ""
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Jira
|
2
|
+
class CLI < Thor
|
3
|
+
|
4
|
+
desc "rename", "Updates the summary of the input ticket"
|
5
|
+
def rename(ticket=Jira::Core.ticket)
|
6
|
+
self.describe(ticket)
|
7
|
+
summary = self.cli.ask("What should the new ticket summary be?")
|
8
|
+
if !summary.strip.empty?
|
9
|
+
params = { fields: { summary: summary } }
|
10
|
+
self.api.put("issue/#{ticket}", params) do |json|
|
11
|
+
puts "Successfully updated ticket #{ticket}'s summary."
|
12
|
+
end
|
13
|
+
else
|
14
|
+
puts "No change made to ticket #{ticket}."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -3,26 +3,26 @@ module Jira
|
|
3
3
|
|
4
4
|
desc "transition", "Transitions the input ticket to the next state"
|
5
5
|
def transition(ticket=Jira::Core.ticket)
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
options['Cancel'] = nil
|
6
|
+
self.api.get("issue/#{ticket}/transitions") do |json|
|
7
|
+
options = {}
|
8
|
+
json['transitions'].each do |transition|
|
9
|
+
options[transition['to']['name']] = transition['id']
|
10
|
+
end
|
11
|
+
options['Cancel'] = nil
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
13
|
+
self.cli.choose do |menu|
|
14
|
+
menu.index = :number
|
15
|
+
menu.index_suffix = ") "
|
16
|
+
menu.header = "Transition #{Jira::Format.ticket(ticket)} to:"
|
17
|
+
menu.prompt = "Transition to: "
|
18
|
+
options.keys.each do |choice|
|
19
|
+
menu.choice choice do
|
20
|
+
transition_id = options[choice]
|
21
|
+
if transition_id.nil?
|
22
|
+
puts "No transition was performed on #{ticket}."
|
23
|
+
else
|
24
|
+
self.api_transition(ticket, transition_id, choice)
|
25
|
+
end
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -32,15 +32,10 @@ module Jira
|
|
32
32
|
protected
|
33
33
|
|
34
34
|
def api_transition(ticket, transition, description)
|
35
|
-
|
36
|
-
|
37
|
-
{ transition: { id: transition } }.to_json
|
38
|
-
)
|
39
|
-
if json.empty?
|
35
|
+
params = { transition: { id: transition } }
|
36
|
+
self.api.post("issue/#{ticket}/transitions", params) do |json|
|
40
37
|
puts "Successfully performed transition (#{description}) "\
|
41
38
|
"on ticket #{ticket}."
|
42
|
-
else
|
43
|
-
puts json['errorMessages'].join('. ')
|
44
39
|
end
|
45
40
|
end
|
46
41
|
|
data/lib/jira/constants.rb
CHANGED
data/lib/jira/mixins.rb
CHANGED
@@ -15,15 +15,20 @@ module Jira
|
|
15
15
|
@highline ||= ::HighLine.new
|
16
16
|
end
|
17
17
|
|
18
|
+
#
|
19
|
+
# @return [Jira::API] Jira API class
|
20
|
+
#
|
21
|
+
def api
|
22
|
+
@api ||= Jira::API.new
|
23
|
+
end
|
24
|
+
|
18
25
|
end
|
19
26
|
end
|
20
27
|
|
21
28
|
class String
|
22
29
|
|
23
30
|
def from_json
|
24
|
-
JSON.parse(self)
|
25
|
-
rescue
|
26
|
-
{}
|
31
|
+
JSON.parse(self) rescue {}
|
27
32
|
end
|
28
33
|
|
29
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jira-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Darren Lin Cheng
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-11-
|
11
|
+
date: 2013-11-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -66,6 +66,8 @@ files:
|
|
66
66
|
- lib/jira/commands/describe.rb
|
67
67
|
- lib/jira/commands/install.rb
|
68
68
|
- lib/jira/commands/log.rb
|
69
|
+
- lib/jira/commands/new.rb
|
70
|
+
- lib/jira/commands/rename.rb
|
69
71
|
- lib/jira/commands/transition.rb
|
70
72
|
- lib/jira/commands/version.rb
|
71
73
|
- lib/jira/constants.rb
|