jira-cli 0.0.8 → 0.0.9
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/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
|