jira-cli 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fc2f76e77a22ebbdd18e710eba5fa4b2d30c4736
4
- data.tar.gz: d270f1d27c5735d6cd7dff37bda1b177380ddca2
3
+ metadata.gz: 7f1bab7c3cccb17ac4d522d2e93b12c6a6a14b5b
4
+ data.tar.gz: edcffe6e4b98d10c1a2932754a5f71c6c906cb2d
5
5
  SHA512:
6
- metadata.gz: 6fb552cdaec39d7b8f00a950cb40d0fbfca3ff44d586782ed94c3690b3f9749f0e00d626c54e9bdcbfc0c1f22ee2bc8e178d432b7de6afc99bc2fc5cdaef20da
7
- data.tar.gz: e11fe2e75a6aae8ef0bd1020625d9c99083764156d11aed4b27586796140c7025cef95968df5cc29d2cec608a48aac5389069d2e97c52d45ec581b094327d79d
6
+ metadata.gz: ce61e0e3b2cdf2956d0fccfa2fc9234bc76054d391e72d463dd50aa40e55014179001bb6652b0d3f5166d880459245dee29c974be6585f20efa67948ac3b587e
7
+ data.tar.gz: 87a09fbb58365dd5400f59ac41ee08796439283c89571804be096ca35300005b8b5a62b15567841a915c0225bc879c91cb6fd197a685d5173e8cc4762df39b43
data/README.md CHANGED
@@ -11,20 +11,31 @@ Ruby gem CLI tool used to manage JIRA workflows leveraging git
11
11
  ### Available Commands
12
12
 
13
13
  jira all # Describes all local branches that match JIRA ticketing syntax
14
+ jira assign # Assign a ticket to a user
14
15
  jira attachments # View ticket attachments
15
- jira browse # Opens the current input ticket in your browser
16
16
  jira comment # Add a comment to the input ticket
17
+ jira commentd # Delete a comment to the input ticket
17
18
  jira comments # Lists the comments of the input ticket
19
+ jira commentu # Update a comment to the input ticket
18
20
  jira commit # Commits uncommitted work with the ticket name and summary.
19
- jira clipboard # Copies the url of the JIRA ticket into the clipboard
21
+ jira delete # Deletes a ticket in JIRA and the git branch
20
22
  jira describe # Describes the input ticket
21
23
  jira install # Guides the user through JIRA installation
22
24
  jira log # Logs work against the input ticket
25
+ jira logd # Deletes work against the input ticket
26
+ jira logs # Lists work against the input ticket
27
+ jira logu # Updates work against the input ticket
23
28
  jira new # Creates a new ticket in JIRA and checks out the git branch
24
29
  jira rename # Updates the summary of the input ticket
25
- jira sprint # Lists all tickets in active sprint
30
+ jira tickets # List the tickets of the input username
26
31
  jira transition # Transitions the input ticket to the next state
32
+ jira unvote # Unvote against the input ticket
33
+ jira unwatch # Unwatch against the input ticket
27
34
  jira version # Displays the version
35
+ jira vote # Vote against the input ticket
36
+ jira votes # List the votes of the input ticket
37
+ jira watch # Watch against the input ticket
38
+ jira watchers # List the watchers of the input ticket
28
39
  jira help [COMMAND] # Describe available commands or one specific command
29
40
 
30
41
  ### Gem Installation
data/lib/jira/api.rb CHANGED
@@ -27,13 +27,13 @@ module Jira
27
27
  protected
28
28
 
29
29
  #
30
- # Defines the API GET, POST, PUT interaction methods
30
+ # Defines the API DELETE, GET, POST, PUT interaction methods
31
31
  #
32
32
  def define_actions
33
33
  #
34
34
  # def method(path, params={})
35
35
  #
36
- # Issue an API GET, POST, or PUT request and return parse JSON
36
+ # Issue an API DELETE, GET, POST, or PUT request and return parse JSON
37
37
  #
38
38
  # @param path [String] API path
39
39
  # @param params [Hash] params to send
@@ -42,7 +42,7 @@ module Jira
42
42
  #
43
43
  # @return [JSON] parased API response
44
44
  #
45
- [:get, :post, :put].each do |method|
45
+ [:delete, :get, :post, :put].each do |method|
46
46
  self.class.send(:define_method, method) do |path, params=nil, verbose=true, &block|
47
47
  params = params.to_json if !params.nil?
48
48
  response = @client.send(
@@ -0,0 +1,17 @@
1
+ module Jira
2
+ class CLI < Thor
3
+
4
+ desc "assign", "Assign a ticket to a user"
5
+ def assign(ticket=Jira::Core.ticket)
6
+ # determine assignee
7
+ assignee = self.io.ask("Assignee (default auto)").strip
8
+ assignee = "-1" if assignee.empty? # automatic assignee is used
9
+
10
+ self.api.put("issue/#{ticket}/assignee", { name: assignee }) do |json|
11
+ return
12
+ end
13
+ puts "Ticket #{ticket} not assigned."
14
+ end
15
+
16
+ end
17
+ end
@@ -1,10 +1,10 @@
1
1
  module Jira
2
2
  class CLI < Thor
3
3
 
4
- desc "browse", "Opens the current input ticket in your browser"
5
- def browse(ticket=Jira::Core.ticket)
6
- system("open #{Jira::Core.url}/browse/#{ticket}")
7
- end
4
+ #desc "browse", "Opens the current input ticket in your browser"
5
+ #def browse(ticket=Jira::Core.ticket)
6
+ # system("open #{Jira::Core.url}/browse/#{ticket}")
7
+ #end
8
8
 
9
9
  end
10
10
  end
@@ -1,10 +1,10 @@
1
1
  module Jira
2
2
  class CLI < Thor
3
3
 
4
- desc "clipboard", "Copies the url of the JIRA ticket into the clipboard"
5
- def clipboard(ticket=Jira::Core.ticket)
6
- `echo #{Jira::Core.url}/browse/#{ticket} | pbcopy`
7
- end
4
+ #desc "clipboard", "Copies the url of the JIRA ticket into the clipboard"
5
+ #def clipboard(ticket=Jira::Core.ticket)
6
+ # `echo #{Jira::Core.url}/browse/#{ticket} | pbcopy`
7
+ #end
8
8
 
9
9
  end
10
10
  end
@@ -3,15 +3,19 @@ module Jira
3
3
 
4
4
  desc "comment", "Add a comment to the input ticket"
5
5
  def comment(ticket=Jira::Core.ticket)
6
- comment = self.io.ask("Leave a comment for ticket #{ticket}")
7
- if comment.strip.empty?
8
- puts "No comment posted."
9
- else
10
- comment.gsub!(/\@[a-zA-Z]+/,'[~\0]').gsub!('[~@','[~')
11
- self.api.post("issue/#{ticket}/comment", { body: comment }) do |json|
12
- puts "Successfully posted your comment."
13
- end
6
+ comment = self.get_comment_body(ticket)
7
+ puts "No comment posted." and return if comment.empty?
8
+
9
+ self.api.post("issue/#{ticket}/comment", { body: comment }) do |json|
10
+ puts "Successfully posted your comment."
11
+ return
14
12
  end
13
+ puts "No comment posted."
14
+ end
15
+
16
+ desc "commentd", "Delete a comment to the input ticket"
17
+ def commentd(ticket=Jira::Core.ticket)
18
+ self.comment_delete(ticket)
15
19
  end
16
20
 
17
21
  desc "comments", "Lists the comments of the input ticket"
@@ -21,18 +25,80 @@ module Jira
21
25
  if comments.count > 0
22
26
  comments.each do |comment|
23
27
  author = comment['author']['displayName']
24
- time = Time.parse(comment['created'])
28
+ time = Time.parse(comment['updated'])
25
29
  body = comment['body']
26
30
 
27
- puts "#{Jira::Format.user(author)} @ "\
31
+ printf "[%2d]", comments.index(comment)
32
+ puts " #{Jira::Format.user(author)} @ "\
28
33
  "#{Jira::Format.time(time)}:\n"\
29
34
  "#{Jira::Format.comment(body)}"
30
35
  end
31
36
  else
32
- puts "There are no comments on issue #{ticket}."
37
+ puts "There are no comments on ticket #{ticket}."
33
38
  end
34
39
  end
35
40
  end
36
41
 
42
+ desc "commentu", "Update a comment to the input ticket"
43
+ def commentu(ticket=Jira::Core.ticket)
44
+ self.comment_update(ticket)
45
+ end
46
+
47
+ protected
48
+
49
+ def comment_delete(ticket)
50
+ comments(ticket) if self.io.agree("List comments for ticket #{ticket}")
51
+
52
+ index = self.get_type_of_index("comment", "delete")
53
+ puts "No comment deleted." and return if index < 0
54
+
55
+ self.api.get("issue/#{ticket}") do |json|
56
+ comments = json['fields']['comment']['comments']
57
+ if index < comments.count
58
+ id = comments[index]['id']
59
+ self.api.delete("issue/#{ticket}/comment/#{id}") do |json|
60
+ puts "Successfully deleted your comment."
61
+ return
62
+ end
63
+ end
64
+ end
65
+ puts "No comment deleted."
66
+ end
67
+
68
+ def comment_update(ticket)
69
+ comments(ticket) if self.io.agree("List comments for ticket #{ticket}")
70
+
71
+ index = self.get_type_of_index("comment", "update")
72
+ puts "No comment updated." and return if index < 0
73
+
74
+ comment = self.get_comment_body(ticket)
75
+ puts "No comment updated." and return if comment.empty?
76
+
77
+ self.api.get("issue/#{ticket}") do |json|
78
+ comments = json['fields']['comment']['comments']
79
+ id = comments[index]['id']
80
+ self.api.put("issue/#{ticket}/comment/#{id}", { body: comment }) do |json|
81
+ puts "Successfully updated your comment."
82
+ return
83
+ end
84
+ end
85
+ puts "No comment updated."
86
+ end
87
+
88
+ #
89
+ # Prompts the user for a comment body, strips it, then
90
+ # returns a substituted version of it
91
+ #
92
+ # @return comment [String] asked comment body
93
+ #
94
+ def get_comment_body(ticket)
95
+ comment = self.io.ask("Leave a comment for ticket #{ticket}").strip
96
+ temp = comment.gsub(/\@[a-zA-Z]+/,'[~\0]')
97
+ temp = comment if temp.nil?
98
+ temp = temp.gsub('[~@','[~')
99
+ comment = temp if !temp.nil?
100
+ comment
101
+ end
102
+
37
103
  end
38
104
  end
@@ -0,0 +1,46 @@
1
+ module Jira
2
+ class CLI < Thor
3
+
4
+ desc "delete", "Deletes a ticket in JIRA and the git branch"
5
+ option :force, type: :boolean, default: false
6
+ def delete(ticket=Jira::Core.ticket)
7
+ force = options[:force]
8
+ self.api.get("issue/#{ticket}") do |json|
9
+ issue_type = json['fields']['issuetype']
10
+ if !issue_type['subtask']
11
+ if !json['fields']['subtasks'].empty?
12
+ force = self.io.agree("Delete all sub-tasks for ticket #{ticket}")
13
+ if !force
14
+ puts "No ticket deleted."
15
+ return
16
+ end
17
+ end
18
+ end
19
+
20
+ self.api.delete("issue/#{ticket}?deleteSubtasks=#{force}") do |json|
21
+ branches = `git branch --list 2> /dev/null`.split(' ')
22
+ branches.delete("*")
23
+ branches.delete("#{ticket}")
24
+ create_branch = self.io.agree("Create branch") if branches.count > 1
25
+ if branches.count == 1 or create_branch
26
+ puts "Creating a new branch."
27
+ new_branch = self.io.ask("Branch").strip
28
+ new_branch.delete!(" ")
29
+ if new_branch.empty?
30
+ puts "No ticket deleted."
31
+ return
32
+ end
33
+ `git branch #{new_branch} 2> /dev/null`
34
+ branches << new_branch
35
+ end
36
+ chosen_branch = self.io.choose("Select a branch", branches)
37
+ `git checkout #{chosen_branch} 2> /dev/null`
38
+ `git branch -D #{ticket} 2> /dev/null`
39
+ return
40
+ end
41
+ end
42
+ puts "No ticket deleted."
43
+ end
44
+
45
+ end
46
+ end
@@ -63,11 +63,16 @@ module Jira
63
63
  self.api.get("issue/#{ticket}", nil, verbose) do |json|
64
64
  summary = json['fields']['summary']
65
65
  status = json['fields']['status']['name']
66
- assignee = json['fields']['assignee']['name']
66
+ assignee = "nil"
67
+ if json['fields'].has_key?("assignee")
68
+ if !json['fields']['assignee'].nil?
69
+ assignee = json['fields']['assignee']['name']
70
+ end
71
+ end
67
72
  description = describe ? "\n" + json['fields']['description'].to_s : ""
68
73
 
69
74
  return Jira::Format.ticket(ticket) +
70
- (star ? Jira::Format.star : " ") + " " +
75
+ (star ? Jira::Format.star : " ") + " \t" +
71
76
  ("(" + Jira::Format.user(assignee) + ")").ljust(20) +
72
77
  Jira::Format.status(status).ljust(26) +
73
78
  Jira::Format.summary(summary) +
@@ -8,16 +8,19 @@ module Jira
8
8
  desc "install", "Guides the user through JIRA installation"
9
9
  def install
10
10
 
11
- create_file(Jira::Core.url_path, nil, verbose:false) do
12
- self.io.ask("Enter your JIRA URL")
13
- end
14
-
15
- create_file(Jira::Core.auth_path, nil, verbose:false) do
16
- username = self.io.ask("Enter your JIRA username")
17
- # TODO - hide password input
18
- password = self.io.ask("Enter your JIRA password")
19
- "#{username}:#{password}"
20
- end
11
+ inifile = IniFile.new(:comment => '#', :encoding => 'UTF-8', :filename => Jira::Core.cli_path)
12
+
13
+ url = self.io.ask("Enter your JIRA URL")
14
+
15
+ username = self.io.ask("Enter your JIRA username")
16
+ password = self.io.ask("Enter your JIRA password", password: true)
17
+
18
+ inifile[:global] = {
19
+ url: url,
20
+ username: username,
21
+ password: password
22
+ }
23
+ inifile.write
21
24
 
22
25
  Jira::Core.send(:discard_memoized)
23
26
  end
@@ -3,11 +3,76 @@ module Jira
3
3
 
4
4
  desc "log", "Logs work against the input ticket"
5
5
  def log(ticket=Jira::Core.ticket)
6
- time_spent = self.io.ask("Time spent on #{ticket}")
6
+ time_spent = self.io.ask("Time spent on ticket #{ticket}")
7
7
  self.api.post("issue/#{ticket}/worklog", { timeSpent: time_spent }) do |json|
8
- puts "Successfully logged #{time_spent} on #{ticket}."
8
+ puts "Successfully logged #{time_spent} on ticket #{ticket}."
9
9
  end
10
10
  end
11
11
 
12
+ desc "logd", "Deletes work against the input ticket"
13
+ def logd(ticket=Jira::Core.ticket)
14
+ logs(ticket) if self.io.agree("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.agree("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
76
+
12
77
  end
13
78
  end
@@ -2,7 +2,7 @@ module Jira
2
2
  class CLI < Thor
3
3
 
4
4
  desc "new", "Creates a new ticket in JIRA and checks out the git branch"
5
- def new
5
+ def new(ticket = Jira::Core.ticket)
6
6
  self.api.get("issue/createmeta") do |meta|
7
7
  # determine project
8
8
  project = self.select_project(meta)
@@ -10,7 +10,12 @@ module Jira
10
10
 
11
11
  # determine issue type
12
12
  issue_type = self.select_issue_type(project)
13
- return if issue_type.empty?
13
+ return if issue_type.nil?
14
+
15
+ # determine parent (ticket)
16
+ parent = nil
17
+ parent = ticket if issue_type['subtask']
18
+ return if !parent.nil? and !Jira::Core.ticket?(parent)
14
19
 
15
20
  # determine summary and description
16
21
  summary = self.io.ask("Summary")
@@ -20,18 +25,19 @@ module Jira
20
25
  params = {
21
26
  fields: {
22
27
  project: { id: project[:id] },
23
- issuetype: { id: issue_type },
28
+ issuetype: { id: issue_type['id'] },
24
29
  summary: summary,
25
30
  description: description
26
31
  }
27
32
  }
33
+ params[:fields][:parent] = { key: parent } if !parent.nil?
28
34
 
29
35
  # post issue to server
30
36
  self.api.post("issue", params) do |json|
31
37
  ticket = json['key']
32
- self.clipboard(ticket)
33
- puts "\nTicket #{Jira::Format.ticket(ticket)} created and copied"\
34
- " to your clipboard."
38
+ if self.io.agree("Assign")
39
+ self.assign(ticket)
40
+ end
35
41
  if self.io.agree("Create branch")
36
42
  `git branch #{ticket} 2> /dev/null`
37
43
  if self.io.agree("Check-out branch")
@@ -75,16 +81,15 @@ module Jira
75
81
  #
76
82
  # @param project_data [Hash] project metadata
77
83
  #
78
- # @return [String] selected issue type
84
+ # @return [Hash] selected issue type
79
85
  #
80
86
  def select_issue_type(project_data)
81
87
  issue_types = {}
82
88
  project_data[:issues].each do |issue_type|
83
- issue_types[issue_type['name']] = issue_type['id']
89
+ issue_types[issue_type['name']] = issue_type
84
90
  end
85
91
  issue_types['Cancel'] = nil
86
92
  choice = self.io.choose("Select an issue type", issue_types.keys)
87
- return '' if choice == 'Cancel'
88
93
  return issue_types[choice]
89
94
  end
90
95
 
@@ -0,0 +1,22 @@
1
+ module Jira
2
+ class CLI < Thor
3
+
4
+ desc "tickets", "List the tickets of the input username"
5
+ def tickets(username=Jira::Core.username)
6
+ self.api.get("search?jql=assignee=#{username}") do |json|
7
+ issues = json['issues']
8
+ if issues.count > 0
9
+ issues.each do |issue|
10
+ ticket = issue['key']
11
+
12
+ printf "[%2d]", issues.index(issue)
13
+ puts " #{Jira::Format.ticket(ticket)}"
14
+ end
15
+ else
16
+ puts "There are no tickets for username #{username}."
17
+ end
18
+ end
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,41 @@
1
+ module Jira
2
+ class CLI < Thor
3
+
4
+ desc "vote", "Vote against the input ticket"
5
+ def vote(ticket=Jira::Core.ticket)
6
+ self.api.post("issue/#{ticket}/votes", Jira::Core.username) do |json|
7
+ puts "Successfully voted against ticket #{ticket}"
8
+ return
9
+ end
10
+ puts "No vote."
11
+ end
12
+
13
+ desc "votes", "List the votes of the input ticket"
14
+ def votes(ticket=Jira::Core.ticket)
15
+ self.api.get("issue/#{ticket}/votes") do |json|
16
+ voters = json['voters']
17
+ if voters.count > 0
18
+ voters.each do |voter|
19
+ displayName = voter['displayName']
20
+
21
+ printf "[%2d]", voters.index(voter)
22
+ puts " #{Jira::Format.user(displayName)}"
23
+ end
24
+ else
25
+ puts "There are no votes on ticket #{ticket}."
26
+ end
27
+ end
28
+ end
29
+
30
+ desc "unvote", "Unvote against the input ticket"
31
+ def unvote(ticket=Jira::Core.ticket)
32
+ username = Jira::Core.username
33
+ self.api.delete("issue/#{ticket}/votes?username=#{username}") do |json|
34
+ puts "Successfully unvoted against ticket #{ticket}"
35
+ return
36
+ end
37
+ puts "No unvote."
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ module Jira
2
+ class CLI < Thor
3
+
4
+ desc "watch", "Watch against the input ticket"
5
+ def watch(ticket=Jira::Core.ticket)
6
+ self.api.post("issue/#{ticket}/watchers", Jira::Core.username) do |json|
7
+ puts "Successfully watched against ticket #{ticket}"
8
+ return
9
+ end
10
+ puts "No watch."
11
+ end
12
+
13
+ desc "watchers", "List the watchers of the input ticket"
14
+ def watchers(ticket=Jira::Core.ticket)
15
+ self.api.get("issue/#{ticket}/watchers") do |json|
16
+ watchers = json['watchers']
17
+ if watchers.count > 0
18
+ watchers.each do |watcher|
19
+ displayName = watcher['displayName']
20
+
21
+ printf "[%2d]", watchers.index(watcher)
22
+ puts " #{Jira::Format.user(displayName)}"
23
+ end
24
+ else
25
+ puts "There are no watchers on ticket #{ticket}."
26
+ end
27
+ end
28
+ end
29
+
30
+ desc "unwatch", "Unwatch against the input ticket"
31
+ def unwatch(ticket=Jira::Core.ticket)
32
+ username = Jira::Core.username
33
+ self.api.delete("issue/#{ticket}/watchers?username=#{username}") do |json|
34
+ puts "Successfully unwatched against ticket #{ticket}"
35
+ return
36
+ end
37
+ puts "No unwatch."
38
+ end
39
+
40
+ end
41
+ end
@@ -1,5 +1,5 @@
1
1
  module Jira
2
2
 
3
- VERSION = "0.1.6"
3
+ VERSION = "0.2.0"
4
4
 
5
5
  end
data/lib/jira/core.rb CHANGED
@@ -7,7 +7,6 @@ module Jira
7
7
  #
8
8
  def setup
9
9
  self.url
10
- self.auth
11
10
  end
12
11
 
13
12
  ### Virtual Attributes
@@ -16,21 +15,21 @@ module Jira
16
15
  # @return [String] JIRA project endpoint
17
16
  #
18
17
  def url
19
- @url ||= ENV['JIRA_URL'] || self.read(self.url_path)
18
+ @url ||= ENV['JIRA_URL'] || self.read(self.cli_path)[:global]['url']
20
19
  end
21
20
 
22
21
  #
23
22
  # @return [String] JIRA username
24
23
  #
25
24
  def username
26
- @username ||= ENV['JIRA_USERNAME'] || self.auth.first
25
+ @username ||= ENV['JIRA_USERNAME'] || self.read(self.cli_path)[:global]['username']
27
26
  end
28
27
 
29
28
  #
30
29
  # @return [String] JIRA password
31
30
  #
32
31
  def password
33
- @password ||= ENV['JIRA_PASSWORD'] || self.auth.last
32
+ @password ||= ENV['JIRA_PASSWORD'] || self.read(self.cli_path)[:global]['password']
34
33
  end
35
34
 
36
35
  #
@@ -61,17 +60,10 @@ module Jira
61
60
  ### Relevant Paths
62
61
 
63
62
  #
64
- # @return [String] path to .jira-url file
63
+ # @return [String] path to .jira-cli file
65
64
  #
66
- def url_path
67
- @url_path ||= self.root_path + "/.jira-url"
68
- end
69
-
70
- #
71
- # @return [String] path to .jira-auth file
72
- #
73
- def auth_path
74
- @auth_path ||= self.root_path + "/.jira-auth"
65
+ def cli_path
66
+ @cli_path ||= self.root_path + "/.jira-cli"
75
67
  end
76
68
 
77
69
  #
@@ -85,16 +77,6 @@ module Jira
85
77
 
86
78
  protected
87
79
 
88
- #
89
- # Determines and parses the auth file
90
- #
91
- # @return [String] JIRA username
92
- # @return [String] JIRA password
93
- #
94
- def auth
95
- @auth ||= self.read(self.auth_path).split(':')
96
- end
97
-
98
80
  ### Core Actions
99
81
 
100
82
  #
@@ -102,7 +84,6 @@ module Jira
102
84
  #
103
85
  def discard_memoized
104
86
  @url = nil
105
- @auth = nil
106
87
  @username = nil
107
88
  @password = nil
108
89
  end
@@ -112,11 +93,11 @@ module Jira
112
93
  #
113
94
  # @param path [String] path of file to read
114
95
  #
115
- # @return [String] contents of the file at the input path
96
+ # @return [Object] IniFile object of the file at the input path
116
97
  #
117
98
  def read(path)
118
99
  self.validate_path!(path)
119
- File.read(path).strip
100
+ IniFile.load(path, { :comment => '#', :encoding => 'UTF-8' })
120
101
  end
121
102
 
122
103
  #
data/lib/jira/io.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  module Jira
2
2
  class IO
3
3
 
4
- def ask(prompt)
5
- Ask.input(prompt)
4
+ def ask(*args)
5
+ Ask.input(*args)
6
6
  end
7
7
 
8
8
  def agree(prompt)
data/lib/jira/mixins.rb CHANGED
@@ -4,6 +4,7 @@ module Jira
4
4
  require 'json'
5
5
  require 'faraday'
6
6
  require 'inquirer'
7
+ require 'inifile'
7
8
  include Thor::Actions
8
9
 
9
10
  protected
@@ -30,6 +31,19 @@ module Jira
30
31
  return klass
31
32
  end
32
33
 
34
+ #
35
+ # Prompts the user for a type of index, then returns the
36
+ # it; failure is < 0
37
+ #
38
+ # @return index [Integer] asked type of index
39
+ #
40
+ def get_type_of_index(command, description)
41
+ response = self.io.ask("Index for #{command} to #{description}").strip
42
+ return -1 if response.empty?
43
+ index = response.to_i
44
+ return -1 if index < 0
45
+ index
46
+ end
33
47
  end
34
48
  end
35
49
 
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.1.6
4
+ version: 0.2.0
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: 2015-10-02 00:00:00.000000000 Z
11
+ date: 2016-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -70,6 +70,26 @@ dependencies:
70
70
  - - ">="
71
71
  - !ruby/object:Gem::Version
72
72
  version: 0.2.0
73
+ - !ruby/object:Gem::Dependency
74
+ name: inifile
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: 2.0.2
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 2.0.2
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 2.0.2
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 2.0.2
73
93
  description: CLI used to manage JIRA workflows leveraging git
74
94
  email: darren@thanx.com
75
95
  executables:
@@ -81,19 +101,23 @@ files:
81
101
  - bin/jira
82
102
  - lib/jira.rb
83
103
  - lib/jira/api.rb
104
+ - lib/jira/commands/assign.rb
84
105
  - lib/jira/commands/attachments.rb
85
106
  - lib/jira/commands/browse.rb
86
107
  - lib/jira/commands/clipboard.rb
87
108
  - lib/jira/commands/comment.rb
88
109
  - lib/jira/commands/commit.rb
110
+ - lib/jira/commands/delete.rb
89
111
  - lib/jira/commands/describe.rb
90
112
  - lib/jira/commands/install.rb
91
113
  - lib/jira/commands/log.rb
92
114
  - lib/jira/commands/new.rb
93
115
  - lib/jira/commands/rename.rb
94
- - lib/jira/commands/sprint.rb
116
+ - lib/jira/commands/tickets.rb
95
117
  - lib/jira/commands/transition.rb
96
118
  - lib/jira/commands/version.rb
119
+ - lib/jira/commands/vote.rb
120
+ - lib/jira/commands/watch.rb
97
121
  - lib/jira/constants.rb
98
122
  - lib/jira/core.rb
99
123
  - lib/jira/exceptions.rb
@@ -120,7 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
144
  version: '0'
121
145
  requirements: []
122
146
  rubyforge_project:
123
- rubygems_version: 2.2.3
147
+ rubygems_version: 2.4.5
124
148
  signing_key:
125
149
  specification_version: 4
126
150
  summary: JIRA CLI
@@ -1,37 +0,0 @@
1
- module Jira
2
- class CLI < Thor
3
-
4
- desc "sprint", "Lists all tickets in active sprint"
5
- def sprint
6
- # TODO
7
- self.api(:agile).get(
8
- 'rapid/charts/sprintreport?rapidViewId=17&sprintId=41'
9
- ) do |response|
10
- groups = {}
11
-
12
- parser = ->(issue){
13
- assignee = issue['assignee']
14
- status = issue['statusName']
15
- groups[assignee] ||= {}
16
- groups[assignee][status] ||= []
17
- groups[assignee][status] << {
18
- ticket: issue['key'],
19
- summary: issue['summary']
20
- }
21
- }
22
-
23
- response['contents']['completedIssues'].each{|issue| parser.call(issue)}
24
- response['contents']['incompletedIssues'].each{|issue| parser.call(issue)}
25
-
26
- groups.each do |user, status_groups|
27
- puts user
28
- status_groups.each do |status, tickets|
29
- puts " " + status
30
- puts " " + tickets.map{|info| info[:ticket] }.join(' ')
31
- end
32
- end
33
- end
34
- end
35
-
36
- end
37
- end