tracker_api 1.9.0 → 1.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-tests.yml +34 -0
  3. data/Gemfile +2 -2
  4. data/README.md +7 -4
  5. data/lib/tracker_api.rb +13 -1
  6. data/lib/tracker_api/client.rb +2 -2
  7. data/lib/tracker_api/endpoints/attachment.rb +3 -1
  8. data/lib/tracker_api/endpoints/blockers.rb +20 -0
  9. data/lib/tracker_api/endpoints/comment.rb +15 -5
  10. data/lib/tracker_api/endpoints/comments.rb +10 -5
  11. data/lib/tracker_api/endpoints/iteration.rb +35 -0
  12. data/lib/tracker_api/endpoints/release.rb +17 -0
  13. data/lib/tracker_api/endpoints/releases.rb +20 -0
  14. data/lib/tracker_api/endpoints/review.rb +21 -0
  15. data/lib/tracker_api/endpoints/reviews.rb +21 -0
  16. data/lib/tracker_api/endpoints/search.rb +1 -1
  17. data/lib/tracker_api/endpoints/stories.rb +10 -0
  18. data/lib/tracker_api/error.rb +12 -2
  19. data/lib/tracker_api/file_utility.rb +1 -1
  20. data/lib/tracker_api/resources/blocker.rb +18 -0
  21. data/lib/tracker_api/resources/comment.rb +2 -2
  22. data/lib/tracker_api/resources/cycle_time_details.rb +21 -0
  23. data/lib/tracker_api/resources/daily_history_container.rb +13 -0
  24. data/lib/tracker_api/resources/epic.rb +10 -1
  25. data/lib/tracker_api/resources/iteration.rb +14 -0
  26. data/lib/tracker_api/resources/project.rb +13 -0
  27. data/lib/tracker_api/resources/release.rb +29 -0
  28. data/lib/tracker_api/resources/review.rb +35 -0
  29. data/lib/tracker_api/resources/review_type.rb +15 -0
  30. data/lib/tracker_api/resources/story.rb +29 -3
  31. data/lib/tracker_api/version.rb +1 -1
  32. data/test/client_test.rb +52 -52
  33. data/test/comment_test.rb +101 -32
  34. data/test/error_test.rb +8 -2
  35. data/test/file_attachment_test.rb +2 -2
  36. data/test/iteration_test.rb +31 -0
  37. data/test/minitest_helper.rb +7 -4
  38. data/test/project_test.rb +59 -47
  39. data/test/release_test.rb +22 -0
  40. data/test/review_test.rb +27 -0
  41. data/test/story_test.rb +65 -48
  42. data/test/task_test.rb +3 -3
  43. data/test/vcr/cassettes/create_epic_attachments.json +1 -0
  44. data/test/vcr/cassettes/create_epic_comment.json +1 -0
  45. data/test/vcr/cassettes/create_epic_comment_with_attachment.json +1 -0
  46. data/test/vcr/cassettes/create_story_attachments.json +1 -0
  47. data/test/vcr/cassettes/create_story_comment.json +1 -1
  48. data/test/vcr/cassettes/create_story_comment_with_attachment.json +1 -0
  49. data/test/vcr/cassettes/delete_epic_attachments.json +1 -0
  50. data/test/vcr/cassettes/delete_epic_comment.json +1 -0
  51. data/test/vcr/cassettes/delete_story_attachments.json +1 -0
  52. data/test/vcr/cassettes/delete_story_comment.json +1 -0
  53. data/test/vcr/cassettes/get_current_iteration.json +1 -1
  54. data/test/vcr/cassettes/get_cycle_time_details.json +1 -0
  55. data/test/vcr/cassettes/get_daily_history_container.json +1 -0
  56. data/test/vcr/cassettes/get_epic.json +1 -0
  57. data/test/vcr/cassettes/get_epic_comments.json +1 -0
  58. data/test/vcr/cassettes/get_releases.json +1 -0
  59. data/test/vcr/cassettes/get_story_reviews.json +1 -0
  60. data/test/vcr/cassettes/release_stories.json +1 -0
  61. data/test/vcr/cassettes/save_epic_comment.json +1 -0
  62. data/test/vcr/cassettes/save_review.json +1 -0
  63. data/test/vcr/cassettes/save_story_comment.json +1 -0
  64. data/test/vcr/cassettes/search_project.json +1 -1
  65. data/test/workspace_test.rb +5 -5
  66. data/tracker_api.gemspec +2 -2
  67. metadata +63 -8
  68. data/.travis.yml +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e5c69ed80fbe1f4d8cb18311a4df2807c7131678c79a4f2c8a54f39fa766a180
4
- data.tar.gz: 9e69d8cfcfb3291ea39ed720685b761430aa12c83f8389ef100bde47f83ddb7b
3
+ metadata.gz: 6d6e9b2c5ba26b416431288d39fe55c9309b753f8ba59572975cf5f424a328a4
4
+ data.tar.gz: 18f138d620e770815349ddad72c728055c7ca35cfdfa89170daf410c4f3db39e
5
5
  SHA512:
6
- metadata.gz: 385942ec74532ff4285005b5477c3e6070f4a5ecdbe51fb2cbd91b8897a518599c31f90e6b91fd8101cb61a494462b8e4563c7f2c9356f258282a4fcaaf4b7d8
7
- data.tar.gz: 92788d5cbc49ae6393fd1012f508c91ffe68e2ff29ee38821abc1dc83e928d5374ea6c78a257bcc3838152e797536f828a9fa7310f98946683c076631aa6c72c
6
+ metadata.gz: fbd90b8f2549b18d5d22f4f1dbf743db182db643be68b4920daaff25f68ebdf3664785903118afc106edf44ae58474e54ac1b582e3b063428f7e6c5f47ec1096
7
+ data.tar.gz: ab1c688fbf08697ecb2705031f82a842357756ff812e0295ffd1dcbac43131db038379225e4265bc554fdc16852af8a205a16d2c0a46978024ee4a5a29cae84a
@@ -0,0 +1,34 @@
1
+ name: Ruby Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ test:
11
+
12
+ runs-on: ubuntu-latest
13
+
14
+ strategy:
15
+ matrix:
16
+ ruby-version: [2.7, 2.6, 2.5]
17
+
18
+ steps:
19
+ - uses: actions/checkout@v2
20
+ - name: Set up Ruby ${{ matrix.ruby-version }}
21
+ uses: ruby/setup-ruby@v1
22
+ with:
23
+ ruby-version: ${{ matrix.ruby-version }}
24
+ - name: Install dependencies
25
+ run: bundle install
26
+ - name: Run tests
27
+ run: bundle exec rake test
28
+ - name: Upload Coverage
29
+ uses: paambaati/codeclimate-action@v2.7.5
30
+ env:
31
+ CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
32
+ with:
33
+ coverageLocations: ${{github.workspace}}/coverage/.resultset.json:simplecov
34
+ if: matrix.ruby-version == '2.7'
data/Gemfile CHANGED
@@ -3,5 +3,5 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in tracker_api.gemspec
4
4
  gemspec
5
5
 
6
- gem 'coveralls', group: :test, require: false
7
-
6
+ # pinned until code climate figures out the new output format https://github.com/codeclimate/test-reporter/issues/418
7
+ gem 'simplecov', '< 0.18', require: false, group: :test
data/README.md CHANGED
@@ -1,10 +1,9 @@
1
1
  # TrackerApi
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/tracker_api.png)](http://badge.fury.io/rb/tracker_api)
4
- [![Build Status](https://travis-ci.org/dashofcode/tracker_api.png?branch=master)](https://travis-ci.org/dashofcode/tracker_api)
5
- [![Code Climate](https://codeclimate.com/github/dashofcode/tracker_api.png)](https://codeclimate.com/github/dashofcode/tracker_api)
6
- [![Coverage Status](https://coveralls.io/repos/dashofcode/tracker_api/badge.png?branch=master)](https://coveralls.io/r/dashofcode/tracker_api?branch=master)
7
- [![Dependency Status](https://gemnasium.com/dashofcode/tracker_api.png)](https://gemnasium.com/dashofcode/tracker_api)
4
+ [![Build Status](https://github.com/ProductPlan/tracker_api/actions/workflows/ruby-tests.yml/badge.svg?branch=master)](https://github.com/ProductPlan/tracker_api/actions)
5
+ [![Maintainability](https://api.codeclimate.com/v1/badges/c4602f519cd748d53492/maintainability)](https://codeclimate.com/github/ProductPlan/tracker_api/maintainability)
6
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/c4602f519cd748d53492/test_coverage)](https://codeclimate.com/github/ProductPlan/tracker_api/test_coverage)
8
7
 
9
8
  This gem allows you to easily use the [Pivotal Tracker v5 API](https://www.pivotaltracker.com/help/api/rest/v5).
10
9
 
@@ -86,6 +85,10 @@ task = story.tasks.first # Get
86
85
  task.complete = true
87
86
  task.save # Mark a task complete
88
87
 
88
+ review = story.reviews.first # Mark a review as complete
89
+ review.status = 'pass'
90
+ review.save
91
+
89
92
  epics = project.epics # Get all epics for a project
90
93
  epic = epics.first
91
94
  label = epic.label # Get an epic's label
data/lib/tracker_api.rb CHANGED
@@ -4,7 +4,7 @@ require 'tracker_api/version'
4
4
  require 'faraday'
5
5
  require 'faraday_middleware'
6
6
  require 'pathname'
7
- require 'mimemagic'
7
+ require 'mini_mime'
8
8
 
9
9
  if defined?(ActiveSupport)
10
10
  require 'active_support/core_ext/object/blank'
@@ -38,8 +38,10 @@ module TrackerApi
38
38
 
39
39
  module Endpoints
40
40
  autoload :Activity, 'tracker_api/endpoints/activity'
41
+ autoload :Blockers, 'tracker_api/endpoints/blockers'
41
42
  autoload :Epic, 'tracker_api/endpoints/epic'
42
43
  autoload :Epics, 'tracker_api/endpoints/epics'
44
+ autoload :Iteration, 'tracker_api/endpoints/iteration'
43
45
  autoload :Iterations, 'tracker_api/endpoints/iterations'
44
46
  autoload :Labels, 'tracker_api/endpoints/labels'
45
47
  autoload :Me, 'tracker_api/endpoints/me'
@@ -62,6 +64,10 @@ module TrackerApi
62
64
  autoload :StoryTransitions, 'tracker_api/endpoints/story_transitions'
63
65
  autoload :Attachment, 'tracker_api/endpoints/attachment'
64
66
  autoload :Attachments, 'tracker_api/endpoints/attachments'
67
+ autoload :Releases, 'tracker_api/endpoints/releases'
68
+ autoload :Release, 'tracker_api/endpoints/release'
69
+ autoload :Review, 'tracker_api/endpoints/review'
70
+ autoload :Reviews, 'tracker_api/endpoints/reviews'
65
71
  end
66
72
 
67
73
  module Resources
@@ -71,6 +77,7 @@ module TrackerApi
71
77
  end
72
78
  autoload :Activity, 'tracker_api/resources/activity'
73
79
  autoload :Account, 'tracker_api/resources/account'
80
+ autoload :Blocker, 'tracker_api/resources/blocker'
74
81
  autoload :Change, 'tracker_api/resources/change'
75
82
  autoload :Epic, 'tracker_api/resources/epic'
76
83
  autoload :EpicsSearchResult, 'tracker_api/resources/epics_search_result'
@@ -93,5 +100,10 @@ module TrackerApi
93
100
  autoload :Webhook, 'tracker_api/resources/webhook'
94
101
  autoload :StoryTransition, 'tracker_api/resources/story_transition'
95
102
  autoload :FileAttachment, 'tracker_api/resources/file_attachment'
103
+ autoload :Release, 'tracker_api/resources/release'
104
+ autoload :CycleTimeDetails, 'tracker_api/resources/cycle_time_details'
105
+ autoload :DailyHistoryContainer, 'tracker_api/resources/daily_history_container'
106
+ autoload :Review, 'tracker_api/resources/review'
107
+ autoload :ReviewType, 'tracker_api/resources/review_type'
96
108
  end
97
109
  end
@@ -25,7 +25,7 @@ module TrackerApi
25
25
  @url = Addressable::URI.parse(url).to_s
26
26
  @api_version = options.fetch(:api_version, '/services/v5')
27
27
  @logger = options.fetch(:logger, ::Logger.new(nil))
28
- adapter = options.fetch(:adapter, :excon)
28
+ adapter = options.fetch(:adapter) { defined?(JRUBY_VERSION) ? :net_http : :excon }
29
29
  connection_options = options.fetch(:connection_options, { ssl: { verify: true } })
30
30
  @auto_paginate = options.fetch(:auto_paginate, true)
31
31
  @token = options[:token]
@@ -223,7 +223,7 @@ module TrackerApi
223
223
  req.body = body
224
224
  end
225
225
  response
226
- rescue Faraday::Error::ClientError => e
226
+ rescue Faraday::ClientError, Faraday::ServerError => e
227
227
  status_code = e.response[:status]
228
228
  case status_code
229
229
  when 400..499 then raise TrackerApi::Errors::ClientError.new(e)
@@ -19,7 +19,9 @@ module TrackerApi
19
19
  # end
20
20
 
21
21
  def get(comment)
22
- data = client.get("/projects/#{comment.project_id}/stories/#{comment.story_id}/comments/#{comment.id}?fields=file_attachments").body["file_attachments"]
22
+ comment_target_slug = !comment.story_id.nil? ? "stories/#{comment.story_id}" : "epics/#{comment.epic_id}"
23
+
24
+ data = client.get("/projects/#{comment.project_id}/#{comment_target_slug}/comments/#{comment.id}?fields=file_attachments").body["file_attachments"]
23
25
  raise Errors::UnexpectedData, 'Array of file attachments expected' unless data.is_a? Array
24
26
 
25
27
  data.map do |file_attachment|
@@ -0,0 +1,20 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Blockers
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(project_id, story_id, params = {})
11
+ data = client.get("/projects/#{project_id}/stories/#{story_id}/blockers", params: params).body
12
+ raise Errors::UnexpectedData, 'Array of Blockers expected' unless data.is_a? Array
13
+
14
+ data.map do |blocker|
15
+ Resources::Blocker.new({ client: client, project_id: project_id }.merge(blocker))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -7,16 +7,24 @@ module TrackerApi
7
7
  @client = client
8
8
  end
9
9
 
10
- def create(project_id, story_id, params={})
11
- data = client.post("/projects/#{project_id}/stories/#{story_id}/comments", params: params).body
10
+ def create(project_id, story_id: nil, epic_id: nil, params: {})
11
+ raise ArgumentError, 'One of story id or epic id must be provided.' if story_id.nil? && epic_id.nil?
12
+
13
+ comment_target_slug = !story_id.nil? ? "stories/#{story_id}" : "epics/#{epic_id}"
14
+
15
+ data = client.post("/projects/#{project_id}/#{comment_target_slug}/comments", params: params).body
12
16
  Resources::Comment.new({ client: client, project_id: project_id }.merge(data))
13
17
  end
14
18
 
15
19
  def update(comment, params={})
16
20
  raise ArgumentError, 'Valid comment required to update.' unless comment.instance_of?(Resources::Comment)
17
21
 
18
- path = "/projects/#{comment.project_id}/stories/#{comment.story_id}/comments/#{comment.id}"
19
- path += "?fields=:default,file_attachments" if params.represented.file_attachment_ids_to_add.present? || params.represented.file_attachment_ids_to_remove.present?
22
+ comment_target_slug = !comment.story_id.nil? ? "stories/#{comment.story_id}" : "epics/#{comment.epic_id}"
23
+
24
+ path = "/projects/#{comment.project_id}/#{comment_target_slug}/comments/#{comment.id}"
25
+ if params.represented.file_attachment_ids_to_add.present? || params.represented.file_attachment_ids_to_remove.present?
26
+ path += "?fields=:default,file_attachments"
27
+ end
20
28
  data = client.put(path, params: params).body
21
29
 
22
30
  comment.attributes = data
@@ -27,7 +35,9 @@ module TrackerApi
27
35
  def delete(comment)
28
36
  raise ArgumentError, 'Valid comment required to update.' unless comment.instance_of?(Resources::Comment)
29
37
 
30
- client.delete("/projects/#{comment.project_id}/stories/#{comment.story_id}/comments/#{comment.id}").body
38
+ comment_target_slug = !comment.story_id.nil? ? "stories/#{comment.story_id}" : "epics/#{comment.epic_id}"
39
+
40
+ client.delete("/projects/#{comment.project_id}/#{comment_target_slug}/comments/#{comment.id}").body
31
41
  end
32
42
  end
33
43
  end
@@ -7,14 +7,19 @@ module TrackerApi
7
7
  @client = client
8
8
  end
9
9
 
10
- def get(project_id, story_id, params={})
11
- data = client.paginate("/projects/#{project_id}/stories/#{story_id}/comments", params: params)
10
+ def get(project_id, story_id: nil, epic_id: nil, params: {})
11
+ raise ArgumentError, 'One of story id or epic id must be provided.' if story_id.nil? && epic_id.nil?
12
+
13
+ comment_target_slug = !story_id.nil? ? "stories/#{story_id}" : "epics/#{epic_id}"
14
+
15
+ data = client.paginate("/projects/#{project_id}/#{comment_target_slug}/comments", params: params)
12
16
  raise Errors::UnexpectedData, 'Array of comments expected' unless data.is_a? Array
13
17
 
14
18
  data.map do |comment|
15
- Resources::Comment.new({ client: client,
16
- project_id: project_id,
17
- story_id: story_id }.merge(comment))
19
+ Resources::Comment.new({
20
+ client: client,
21
+ project_id: project_id
22
+ }.merge(comment))
18
23
  end
19
24
  end
20
25
  end
@@ -0,0 +1,35 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Iteration
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(project_id, iteration_number)
11
+ data = client.get("/projects/#{project_id}/iterations/#{iteration_number}").body
12
+
13
+ Resources::Iteration.new({ client: client, project_id: project_id }.merge(data))
14
+ end
15
+
16
+ def get_analytics_cycle_time_details(project_id, iteration_number)
17
+ data = client.paginate("/projects/#{project_id}/iterations/#{iteration_number}/analytics/cycle_time_details")
18
+ raise Errors::UnexpectedData, 'Array of cycle time details expected' unless data.is_a? Array
19
+
20
+ data.map do |cycle_time_details|
21
+ Resources::CycleTimeDetails.new(
22
+ { project_id: project_id, iteration_number: iteration_number }.merge(cycle_time_details)
23
+ )
24
+ end
25
+ end
26
+
27
+ def get_history(project_id, iteration_number)
28
+ data = client.get("/projects/#{project_id}/history/iterations/#{iteration_number}/days").body
29
+ raise Errors::UnexpectedData, 'Hash of history data expected' unless data.is_a? Hash
30
+
31
+ Resources::DailyHistoryContainer.new({ project_id: project_id, iteration_number: iteration_number }.merge(data))
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,17 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Release
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(project_id, id, params={})
11
+ data = client.get("/projects/#{project_id}/releases/#{id}", params: params).body
12
+
13
+ Resources::Release.new({ client: client }.merge(data))
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Releases
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(project_id, params={})
11
+ data = client.paginate("/projects/#{project_id}/releases", params: params)
12
+ raise Errors::UnexpectedData, 'Array of releases expected' unless data.is_a? Array
13
+
14
+ data.map do |release|
15
+ Resources::Release.new({ client: client, project_id: project_id }.merge(release))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Review
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def update(review, params = {})
11
+ raise ArgumentError, 'Valid review required to update.' unless review.instance_of?(Resources::Review)
12
+
13
+ data = client.put("/projects/#{review.project_id}/stories/#{review.story_id}/reviews/#{review.id}", params: params).body
14
+
15
+ review.attributes = data
16
+ review.clean!
17
+ review
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Reviews
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(project_id, story_id, params={})
11
+ params[:fields] ||= ":default,review_type"
12
+ data = client.paginate("/projects/#{project_id}/stories/#{story_id}/reviews", params: params)
13
+ raise Errors::UnexpectedData, 'Successful responses to this request return an array containing zero or more instances of the review resource. This response was not an array.' unless data.is_a? Array
14
+
15
+ data.map do |review|
16
+ Resources::Review.new({ client: client, project_id: project_id }.merge(review))
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -10,7 +10,7 @@ module TrackerApi
10
10
  def get(project_id, query, options={})
11
11
  raise ArgumentError, 'Valid query string required to search' unless query.is_a?(String)
12
12
 
13
- options.key?(:body) ? options[:body][:query] = query : options[:body] = { query: query }
13
+ options[:params] = { query: query }
14
14
  data = client.get("/projects/#{project_id}/search", options).body
15
15
 
16
16
  raise Errors::UnexpectedData, 'Hash of search results expect' unless data.is_a? Hash
@@ -17,6 +17,16 @@ module TrackerApi
17
17
  Resources::Story.new({ client: client, project_id: project_id }.merge(story))
18
18
  end
19
19
  end
20
+
21
+ def get_release(project_id, release_id, params={})
22
+ data = client.paginate("/projects/#{project_id}/releases/#{release_id}/stories", params: params)
23
+
24
+ raise Errors::UnexpectedData, 'Array of stories expected' unless data.is_a? Array
25
+
26
+ data.map do |story|
27
+ Resources::Story.new({ client: client, project_id: project_id }.merge(story))
28
+ end
29
+ end
20
30
  end
21
31
  end
22
32
  end
@@ -5,14 +5,24 @@ module TrackerApi
5
5
  def initialize(wrapped_exception)
6
6
  @wrapped_exception = wrapped_exception
7
7
  @response = wrapped_exception.response
8
- message = if wrapped_exception.is_a?(Faraday::Error::ParsingError)
8
+ message = if wrapped_exception.is_a?(Faraday::ParsingError)
9
9
  wrapped_exception.message
10
- elsif wrapped_exception.is_a?(Faraday::Error::ClientError)
10
+ elsif faraday_response_error?(wrapped_exception)
11
11
  wrapped_exception.response.inspect
12
12
  else
13
13
  wrapped_exception.instance_variable_get(:@wrapped_exception).inspect
14
14
  end
15
15
  super(message)
16
16
  end
17
+
18
+ private
19
+
20
+ # faraday 16.0 re-organized their errors. The errors we're interested in,
21
+ # Faraday::ClientError before 16.0 and Faraday::ServerError introduced in
22
+ # 16.0, are represented by this conditional.
23
+ def faraday_response_error?(wrapped_exception)
24
+ wrapped_exception.is_a?(Faraday::Error) &&
25
+ wrapped_exception.respond_to?(:response)
26
+ end
17
27
  end
18
28
  end
@@ -2,7 +2,7 @@ module TrackerApi
2
2
  class FileUtility
3
3
  class << self
4
4
  def get_file_upload(file)
5
- mime_type = MimeMagic.by_path(file)
5
+ mime_type = MiniMime.lookup_by_filename(file)
6
6
  { :file => Faraday::UploadIO.new(file, mime_type) }
7
7
  end
8
8
 
@@ -0,0 +1,18 @@
1
+ module TrackerApi
2
+ module Resources
3
+ class Blocker
4
+ include Shared::Base
5
+
6
+ attribute :client
7
+ attribute :project_id, Integer
8
+
9
+ attribute :story_id, Integer
10
+ attribute :person_id, Integer
11
+ attribute :description, String
12
+ attribute :resolved, Boolean
13
+ attribute :created_at, DateTime
14
+ attribute :updated_at, DateTime
15
+ attribute :kind, String
16
+ end
17
+ end
18
+ end