jira-cli 0.1.6 → 0.2.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.
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