tracker_api 1.9.0 → 1.13.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 (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