terjira 0.1.1 → 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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -1
  3. data/Gemfile.lock +3 -3
  4. data/README.md +14 -15
  5. data/bin/console +1 -1
  6. data/bin/jira +11 -3
  7. data/bin/terjira +22 -0
  8. data/lib/terjira/base_cli.rb +5 -3
  9. data/lib/terjira/board_cli.rb +17 -2
  10. data/lib/terjira/client/agile.rb +10 -13
  11. data/lib/terjira/client/auth_option_builder.rb +1 -1
  12. data/lib/terjira/client/base.rb +9 -12
  13. data/lib/terjira/client/board.rb +13 -3
  14. data/lib/terjira/client/field.rb +12 -2
  15. data/lib/terjira/client/issue.rb +15 -13
  16. data/lib/terjira/client/issuetype.rb +18 -0
  17. data/lib/terjira/client/jql_builder.rb +25 -0
  18. data/lib/terjira/client/priority.rb +1 -1
  19. data/lib/terjira/client/resolution.rb +1 -1
  20. data/lib/terjira/client/status.rb +1 -1
  21. data/lib/terjira/client/user.rb +5 -6
  22. data/lib/terjira/ext/jira_ruby.rb +12 -4
  23. data/lib/terjira/ext/tty_prompt.rb +0 -3
  24. data/lib/terjira/issue_cli.rb +11 -7
  25. data/lib/terjira/option_support/option_selector.rb +20 -9
  26. data/lib/terjira/option_support/shared_options.rb +4 -2
  27. data/lib/terjira/option_supportable.rb +24 -0
  28. data/lib/terjira/presenters/common_presenter.rb +13 -4
  29. data/lib/terjira/presenters/issue_presenter.rb +115 -97
  30. data/lib/terjira/presenters/project_presenter.rb +1 -1
  31. data/lib/terjira/presenters/sprint_presenter.rb +9 -9
  32. data/lib/terjira/sprint_cli.rb +1 -0
  33. data/lib/terjira/utils/file_cache.rb +26 -26
  34. data/lib/terjira/version.rb +1 -1
  35. data/lib/terjira.rb +11 -0
  36. data/terjira.gemspec +4 -4
  37. metadata +11 -11
  38. data/lib/terjira/client/jql_query_builer.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5592eeb887c0b8ce2a4437c36c3e2468417f54f3
4
- data.tar.gz: 49483f95737dc6ae8f57d7871c8db30ce4da59d3
3
+ metadata.gz: 1daef227221455846fa59674d6cfeb9735d1e33d
4
+ data.tar.gz: 5dd7bbe7f90499eaf61ff4300ae5518f1a3336b3
5
5
  SHA512:
6
- metadata.gz: 82a1c765c3328a83d96e4e6e5c800acaee4fac814f672d2f59d11e8292d650d7ea1c531aef9ec42c8d97f408aabd67d2a5697f5cfd24f85b0a135211fa8d5a4f
7
- data.tar.gz: 04eea6bbe20ae4474c7b518374ad3a63fefea7f51030b7036e91b2018be799fb99670f2eba6cc51df25d4260e884d17806e2f84babbfcd403c72bb2dcdc5e8c5
6
+ metadata.gz: 6124824ac122ea72b0e7077956371b6803cd848a8a454bbb03c4e25de2a8e99902e64a5fd01763925b1cecfa9ac7e04457749c7b56ddd2c530d178bbdfd025f8
7
+ data.tar.gz: 4ecc886b8ab99b2bc3ddfb9f9694f6baba32f5b63484f9468ac9dd6368e5428108e4cedfb74e291024f1ce8e9a0326e6a237d79284c912f4828441836358f8b2
data/.rubocop.yml CHANGED
@@ -1,14 +1,23 @@
1
1
  AllCops:
2
2
  Exclude:
3
+ - 'bin/*'
3
4
  - '*.gemspec'
5
+ - 'lib/terjira/ext/**/*'
6
+ - 'Rakefile'
4
7
 
5
8
  Style/Documentation:
6
9
  Enabled: false
7
10
  Style/EachWithObject:
8
11
  Enabled: false
12
+ Style/RescueModifier:
13
+ Enabled: false
9
14
 
10
15
  Lint/AssignmentInCondition:
11
16
  Enabled: false
17
+ Lint/Eval:
18
+ Enabled: false
19
+ Lint/ImplicitStringConcatenation:
20
+ Enabled: false
12
21
 
13
22
  Metrics/BlockLength:
14
23
  Enabled: false
@@ -20,7 +29,7 @@ Metrics/AbcSize:
20
29
  Max: 20
21
30
 
22
31
  Metrics/MethodLength:
23
- Max: 20
32
+ Max: 30
24
33
 
25
34
  Metrics/LineLength:
26
35
  Max: 100
data/Gemfile.lock CHANGED
@@ -6,9 +6,9 @@ PATH
6
6
  jira-ruby (~> 1.1)
7
7
  pastel (~> 0.6.1)
8
8
  thor (~> 0.19)
9
- tty-prompt (~> 0.8.0)
10
- tty-spinner (~> 0.4.1)
11
- tty-table (~> 0.6.0)
9
+ tty-prompt (~> 0.8)
10
+ tty-spinner (~> 0.4)
11
+ tty-table (~> 0.6)
12
12
 
13
13
  GEM
14
14
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -5,42 +5,41 @@
5
5
 
6
6
  # Terjira
7
7
 
8
- Terjira is a very interactive and easy to use command line interface for Jira.
8
+ Terjira is interactive and easy to use command line interface (or Application) for Jira. You do not need to remember reosurce key or id. Terjira suggests with interactive prompt.
9
9
 
10
+ Your Jira must support Rest API 2.0 and Agile Rest API 1.0
10
11
 
11
- I'm working now..
12
+
13
+ **I'm working now..**
12
14
 
13
15
  ## Installation
14
16
 
15
- Add this line to your application's Gemfile:
17
+ Install it yourself as:
16
18
 
17
- ```ruby
18
- gem 'terjira'
19
- ```
19
+ $ gem install terjira
20
20
 
21
- And then execute:
21
+ If you have permission problem,
22
22
 
23
- $ bundle
23
+ $ sudo gem install terjira
24
24
 
25
- Or install it yourself as:
25
+ # or
26
26
 
27
- $ gem install terjira
27
+ $ gem install terjira --user-install
28
+ # You need to export your gem path
28
29
 
29
30
  ## Usage
30
31
 
31
- TODO: Write usage instructions here
32
32
 
33
- * Mock data is from jira-ruby
34
33
 
35
34
  ## Development
36
35
 
37
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
36
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rspec spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
38
37
 
39
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
38
+ To install this gem onto your local machine, run `bundle exec rake install`.
40
39
 
41
40
  ## Contributing
42
41
 
43
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/terjira. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
42
+ Bug reports and pull requests are welcome on GitHub at https://github.com/keepcosmos/terjira. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
44
43
 
45
44
 
46
45
  ## License
data/bin/console CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # Do I need bundler setup?
3
- # require "bundler/setup"
3
+ require "bundler/setup"
4
4
  require "terjira"
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
data/bin/jira CHANGED
@@ -1,14 +1,22 @@
1
1
  #!/usr/bin/env ruby
2
+
2
3
  # Do I need bundler setup?
3
4
  # require 'bundler/setup'
4
5
  require 'terjira'
5
6
  require 'json'
7
+ require 'pastel'
6
8
 
7
9
  begin
8
10
  Terjira::CLI.start(ARGV)
11
+ rescue SystemExit, Interrupt
9
12
  rescue JIRA::HTTPError => e
10
13
  message = JSON.parse(e.response.body)
11
- error_message = message['errorMessages']
12
- error_message = error_message.join(' ') if error_message.is_a? Array
13
- puts "#{e.message} :: #{error_message}"
14
+ pastel = Pastel.new
15
+ if message['errorMessages'].present?
16
+ puts pastel.red(message['errorMessages'].join("\n"))
17
+ else
18
+ puts pastel.red(e.message.to_s + "\n" + e.response.body)
19
+ end
20
+ rescue => e
21
+ puts Pastel.new.dim(e.message)
14
22
  end
data/bin/terjira ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Do I need bundler setup?
4
+ require 'bundler/setup'
5
+ require 'terjira'
6
+ require 'json'
7
+ require 'pastel'
8
+
9
+ begin
10
+ Terjira::CLI.start(ARGV)
11
+ rescue SystemExit, Interrupt
12
+ rescue JIRA::HTTPError => e
13
+ message = JSON.parse(e.response.body)
14
+ pastel = Pastel.new
15
+ if message['errorMessages'].present?
16
+ puts pastel.red(message['errorMessages'].join("\n"))
17
+ else
18
+ puts pastel.red(e.message.to_s + "\n" + e.response.body)
19
+ end
20
+ rescue => e
21
+ puts Pastel.new.dim(e.message)
22
+ end
@@ -1,11 +1,13 @@
1
1
  require 'thor'
2
2
 
3
3
  require_relative 'option_supportable'
4
- Dir[File.dirname(__FILE__) + "/presenters/*.rb"].each { |f| require f }
4
+ Dir[File.dirname(__FILE__) + '/presenters/*.rb'].each { |f| require f }
5
5
 
6
6
  module Terjira
7
+ # Jira client based on jira-ruby gem
7
8
  module Client
8
- %w[Base Field Project Board Sprint Issue User Status Resolution Priority RapidView Agile].each do |klass|
9
+ %w(Base Field Issuetype Project Board Sprint Issue User
10
+ Status Resolution Priority RapidView Agile).each do |klass|
9
11
  autoload klass, "terjira/client/#{klass.gsub(/(.)([A-Z](?=[a-z]))/,'\1_\2').downcase}"
10
12
  end
11
13
  end
@@ -19,7 +21,7 @@ module Terjira
19
21
  include BoardPresenter
20
22
  include SprintPresenter
21
23
 
22
- def self.banner(command, namespace = nil, subcommand = false)
24
+ def self.banner(command, _namespace = nil, _subcommand = false)
23
25
  "#{basename} #{subcommand_prefix} #{command.usage}"
24
26
  end
25
27
 
@@ -2,11 +2,26 @@ require_relative 'base_cli'
2
2
 
3
3
  module Terjira
4
4
  class BoardCLI < BaseCLI
5
- desc "list(ls)", "list all boards"
5
+ no_commands do
6
+ def client_class
7
+ Client::Board
8
+ end
9
+ end
10
+
11
+ desc "( ls | list)", "list all boards"
6
12
  map ls: :list
7
13
  def list
8
- boards = Client::Board.all
14
+ boards = client_class.all
9
15
  render_boards_summary(boards.sort_by { |b| b.id })
10
16
  end
17
+
18
+ desc "backlog", "Backlog from the board"
19
+ jira_options :board, :assignee, :issuetype, :priority
20
+ def backlog
21
+ opts = suggest_options(required: [:board])
22
+ board = opts.delete(:board)
23
+ issues = client_class.backlog(board.key_value, opts)
24
+ render_issues(issues)
25
+ end
11
26
  end
12
27
  end
@@ -7,22 +7,22 @@ module Terjira
7
7
  delegate :all, :get_sprints, :backlog_issues, to: :resource
8
8
 
9
9
  def project_by_board(board_id)
10
- resp = agile_api_get("board/#{board_id}/project")
10
+ agile_api_get("board/#{board_id}/project")
11
11
  end
12
12
 
13
13
  def boards
14
- all["values"]
14
+ all['values']
15
15
  end
16
16
 
17
- def sprints(board_id, options = {})
18
- sprints = get_sprints(board_id)["values"]
17
+ def sprints(board_id)
18
+ sprints = get_sprints(board_id)['values']
19
19
  sprints.sort_by do |sprint|
20
- if sprint["state"] == 'active'
21
- [0, sprint["id"]]
22
- elsif sprint["state"] == 'future'
23
- [1, sprint["id"]]
24
- elsif sprint["state"] == 'closed'
25
- [2, sprint["id"] * -1]
20
+ if sprint['state'] == 'active'
21
+ [0, sprint['id']]
22
+ elsif sprint['state'] == 'future'
23
+ [1, sprint['id']]
24
+ elsif sprint['state'] == 'closed'
25
+ [2, sprint['id'] * -1]
26
26
  else
27
27
  [3, 0]
28
28
  end
@@ -32,9 +32,6 @@ module Terjira
32
32
  def backlog_issues(board_id)
33
33
  get_backlog_issues(board_id)
34
34
  end
35
-
36
- def sprint_issues(board_id)
37
- end
38
35
  end
39
36
  end
40
37
  end
@@ -17,7 +17,7 @@ module Terjira
17
17
  end
18
18
 
19
19
  def expire_auth_options(cache_key = AUTH_CACHE_KEY)
20
- auth_file_cache.delete(cache_key)
20
+ Terjira::FileCache.clear_all
21
21
  end
22
22
 
23
23
  def build_auth_options_by_tty
@@ -1,23 +1,22 @@
1
- require_relative 'jql_query_builer'
1
+ require_relative 'jql_builder'
2
2
  require_relative 'auth_option_builder'
3
3
 
4
4
  module Terjira
5
5
  module Client
6
6
  # Abstract class to delegate jira-ruby resource class
7
7
  class Base
8
- extend JQLQueryBuilder
8
+ extend JQLBuilder
9
9
  extend AuthOptionBuilder
10
10
 
11
11
  DEFAULT_CACHE_SEC = 60
12
- DEFAULT_API_PATH = "/rest/api/2/"
13
- AGILE_API_PATH = "/rest/agile/1.0/"
12
+ DEFAULT_API_PATH = '/rest/api/2/'.freeze
13
+ AGILE_API_PATH = '/rest/agile/1.0/'.freeze
14
14
 
15
15
  class << self
16
-
17
16
  delegate :build, to: :resource
18
17
 
19
18
  def client
20
- @@client ||= JIRA::Client.new(build_auth_options)
19
+ @client ||= JIRA::Client.new(build_auth_options)
21
20
  end
22
21
 
23
22
  def resource
@@ -29,7 +28,7 @@ module Terjira
29
28
  end
30
29
 
31
30
  def class_name
32
- self.to_s.split("::").last
31
+ to_s.split('::').last
33
32
  end
34
33
 
35
34
  def cache(options = {})
@@ -38,16 +37,14 @@ module Terjira
38
37
  end
39
38
 
40
39
  # define `#api_get(post, put, delete)` and `#agile_api_get(post, put, delete)`
41
- { DEFAULT_API_PATH => "api_",
42
- AGILE_API_PATH => "agile_api_"
43
- }.each do |url_prefix, method_prefix|
44
-
40
+ { DEFAULT_API_PATH => 'api_',
41
+ AGILE_API_PATH => 'agile_api_' }.each do |url_prefix, method_prefix|
45
42
  [:get, :delete].each do |http_method|
46
43
  method_name = "#{method_prefix}#{http_method}"
47
44
  define_method(method_name) do |path, params = {}, headers = {}|
48
45
  url = url_prefix + path
49
46
  if params.present?
50
- params.reject! { |k, v| v.blank? }
47
+ params.reject! { |_k, v| v.blank? }
51
48
  url += "?#{URI.encode_www_form(params)}"
52
49
  end
53
50
  parse_body client.send(http_method, url, headers)
@@ -6,13 +6,23 @@ module Terjira
6
6
 
7
7
  def all(options = {})
8
8
  params = options.slice(:type)
9
- resp = agile_api_get("board", params)
10
- resp["values"].map { |value| build(value) }
9
+ resp = agile_api_get('board', params)
10
+ resp['values'].map { |value| build(value) }
11
11
  end
12
12
 
13
13
  def find(board_id)
14
14
  resp = agile_api_get("board/#{board_id}")
15
- self.build(resp)
15
+ build(resp)
16
+ end
17
+
18
+ def backlog(board_id, options = {})
19
+ jql = build_jql(options)
20
+ resp = if jql.present?
21
+ agile_api_get("board/#{board_id}/backlog", jql: jql)
22
+ else
23
+ agile_api_get("board/#{board_id}/backlog")
24
+ end
25
+ resp["issues"].map { |issue| Issue.build(issue) }
16
26
  end
17
27
  end
18
28
  end
@@ -5,11 +5,21 @@ module Terjira
5
5
  class Field < Base
6
6
  class << self
7
7
  def all
8
- @all_fields ||= resource.all
8
+ @all_fields ||= file_cache.fetch("all") do
9
+ resource.all
10
+ end
9
11
  end
10
12
 
11
13
  def epic_name
12
- all.find { |field| field.name == "Epic Name" }
14
+ all.find { |field| field.name == 'Epic Name' }
15
+ end
16
+
17
+ def epiclink
18
+ all.find { |field| field.name == 'Epic Link' }
19
+ end
20
+
21
+ def file_cache
22
+ Terjira::FileCache.new("resource/fields", 60 * 60 * 24)
13
23
  end
14
24
  end
15
25
  end
@@ -5,22 +5,21 @@ module Terjira
5
5
  class Issue < Base
6
6
  class << self
7
7
  delegate :build, :find, to: :resource
8
- ISSUE_JQL_KEYS = [:sprint, :assignee, :reporter, :project, :issuetype, :priority, :status, :statusCategory]
9
8
 
10
9
  def all(options = {})
11
- opts = options.slice(*ISSUE_JQL_KEYS)
12
10
  return resource.all if options.blank?
13
11
  max_results = options.delete(:max_results) || 500
14
- resource.jql(build_jql_query(opts), max_results: max_results)
12
+ resource.jql(build_jql(options), max_results: max_results)
15
13
  end
16
14
 
17
- def find(issue, options = {})
18
- resp = api_get("issue/#{issue.key_value}", options)
19
- build(resp)
15
+ def all_epic_issues(epic)
16
+ resp = agile_api_get("epic/#{epic.key}/issue")
17
+ resp["issues"].map { |issue| build(issue) }
20
18
  end
21
19
 
22
- def current_my_issues
23
- jql("assignee = #{self.key_value} AND statusCategory != 'Done'")
20
+ def find(issue, options = {})
21
+ resp = agile_api_get("issue/#{issue.key_value}", options)
22
+ build(resp)
24
23
  end
25
24
 
26
25
  def assign(issue, assignee)
@@ -29,7 +28,7 @@ module Terjira
29
28
  end
30
29
 
31
30
  def write_comment(issue, message)
32
- resp = api_post("issue/#{issue.key_value}/comment", { body: message }.to_json)
31
+ api_post("issue/#{issue.key_value}/comment", { body: message }.to_json)
33
32
  find(issue)
34
33
  end
35
34
 
@@ -39,9 +38,8 @@ module Terjira
39
38
  params.merge!(transition_param)
40
39
  end
41
40
 
42
- resp = api_post "issue", params.to_json
43
- result_id = resp["id"]
44
- find(result_id)
41
+ resp = api_post 'issue', params.to_json
42
+ find(resp['id'])
45
43
  end
46
44
 
47
45
  def update(issue, options = {})
@@ -80,7 +78,7 @@ module Terjira
80
78
  params = {}
81
79
 
82
80
  custom_fields = options.keys.select { |k| k.to_s =~ /^customfield/ }
83
- (custom_fields + [:summary, :description]).each do |k, v|
81
+ (custom_fields + [:summary, :description]).each do |k, _v|
84
82
  params[k] = opts.delete(k) if opts.key?(k)
85
83
  end
86
84
 
@@ -88,6 +86,10 @@ module Terjira
88
86
  params[:project] = { key: opts.delete(:project).key_value }
89
87
  end
90
88
 
89
+ if opts.key?(:parent)
90
+ params[:parent] = { key: opts.delete(:parent).key_value }
91
+ end
92
+
91
93
  opts.each do |k, v|
92
94
  params[k] = convert_param_key_value_hash(v)
93
95
  end
@@ -0,0 +1,18 @@
1
+ require_relative 'base'
2
+
3
+ module Terjira
4
+ module Client
5
+ class Issuetype < Base
6
+ class << self
7
+ def all
8
+ resp = api_get("issuetype")
9
+ resp.map { |issuetype| build(issuetype) }
10
+ end
11
+
12
+ def subtask_issuetypes
13
+ all.select(&:subtask)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ module Terjira
2
+ module Client
3
+ module JQLBuilder
4
+ JQL_KEYS = %w(sprint assignee issuetype priority project status statusCategory).freeze
5
+
6
+ def build_jql(options = {})
7
+ q_options = options.inject({}) do |memo, (k, v)|
8
+ memo[k.to_s] = v
9
+ memo
10
+ end.slice(*JQL_KEYS)
11
+
12
+ query = q_options.map do |key, value|
13
+ if value.is_a? Array
14
+ values = value.map { |v| "\"#{v.key_value}\"" }.join(',')
15
+ "#{key} IN (#{values})"
16
+ else
17
+ "#{key}=#{value.key_value}"
18
+ end
19
+ end.reject(&:blank?).join(' AND ')
20
+
21
+ query
22
+ end
23
+ end
24
+ end
25
+ end
@@ -5,7 +5,7 @@ module Terjira
5
5
  class Priority < Base
6
6
  class << self
7
7
  def all
8
- resp = api_get "priority"
8
+ resp = api_get 'priority'
9
9
  resp.map { |priority| build(priority) }
10
10
  end
11
11
  end
@@ -5,7 +5,7 @@ module Terjira
5
5
  class Resolution < Base
6
6
  class << self
7
7
  def all
8
- resp = api_get("resolution")
8
+ resp = api_get('resolution')
9
9
  resp.map { |resolution| build(resolution) }
10
10
  end
11
11
  end
@@ -6,7 +6,7 @@ module Terjira
6
6
  class << self
7
7
  def all(project)
8
8
  resp = api_get "project/#{project.key_value}/statuses"
9
- statuses_json = resp.map { |issuetype| issuetype["statuses"] }.flatten.uniq
9
+ statuses_json = resp.map { |issuetype| issuetype['statuses'] }.flatten.uniq
10
10
  statuses_json.map { |status| build(status) }
11
11
  end
12
12
  end
@@ -6,10 +6,10 @@ module Terjira
6
6
  class << self
7
7
  def assignables_by_project(project)
8
8
  if project.is_a? Array
9
- keys = project.map(&:key_value).join(",")
10
- fetch_assignables "user/assignable/multiProjectSearch", {projectKeys: keys }
9
+ keys = project.map(&:key_value).join(',')
10
+ fetch_assignables 'user/assignable/multiProjectSearch', projectKeys: keys
11
11
  else
12
- fetch_assignables "user/assignable/search", { project: project.key_value }
12
+ fetch_assignables 'user/assignable/search', project: project.key_value
13
13
  end
14
14
  end
15
15
 
@@ -28,15 +28,14 @@ module Terjira
28
28
  end
29
29
 
30
30
  def assignables_by_issue(issue)
31
- fetch_assignables "user/assignable/search", {issueKey: issue.key_value }
31
+ fetch_assignables 'user/assignable/search', issueKey: issue.key_value
32
32
  end
33
33
 
34
34
  private
35
35
 
36
36
  def fetch_assignables(path, params)
37
37
  resp = api_get(path, params)
38
- resp.map { |user| build(user) }.
39
- reject { |user| user.key_value =~ /^addon/ }
38
+ resp.map { |user| build(user) }.reject { |user| user.key_value =~ /^addon/ }
40
39
  end
41
40
  end
42
41
  end
@@ -9,15 +9,12 @@ module JIRA
9
9
  alias origin_make_request make_request
10
10
 
11
11
  def make_request(http_method, path, body = '', headers = {})
12
- title = http_method.to_s.upcase
13
- title = Pastel.new.dim(title)
12
+ title = Pastel.new.dim(http_method.to_s.upcase)
14
13
  spinner = TTY::Spinner.new ":spinner #{title}", format: :dots, clear: true
15
14
  result = nil
16
-
17
15
  spinner.run do
18
16
  result = origin_make_request(http_method, path, body, headers)
19
17
  end
20
-
21
18
  result
22
19
  end
23
20
  end
@@ -33,16 +30,27 @@ module JIRA
33
30
  class BoardFactory < JIRA::BaseFactory # :nodoc:
34
31
  end
35
32
 
33
+ class EpicFactory < JIRA::BaseFactory # :nodoc:
34
+ end
35
+
36
36
  class Board < JIRA::Base
37
37
  def self.key_attribute; :id; end
38
38
  end
39
39
 
40
+ class Epic < JIRA::Base
41
+ def self.key_attribute; :key; end
42
+ end
43
+
40
44
  class User
41
45
  def self.key_attribute; :name; end
42
46
  end
43
47
 
44
48
  class Issue
45
49
  def self.key_attribute; :key; end
50
+ has_one :epic, class: JIRA::Resource::Epic, nested_under: 'fields'
51
+ has_one :sprint, class: JIRA::Resource::Sprint, nested_under: 'fields'
52
+ has_one :parent, class: JIRA::Resource::Issue, nested_under: 'fields'
53
+ has_many :subtasks, class: JIRA::Resource::Issue, nested_under: 'fields'
46
54
  end
47
55
 
48
56
  class Issuetype
@@ -3,9 +3,6 @@ require 'tty-prompt'
3
3
  module TTY
4
4
  class Prompt
5
5
  class Question
6
- # Decide how to handle input from user
7
- #
8
- # @api private
9
6
  def process_input
10
7
  @input = read_input
11
8
  if Utils.blank?(@input)