bugsnag-api 2.0.0 → 2.1.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 (89) hide show
  1. checksums.yaml +5 -5
  2. data/.buildkite/pipeline.yml +6 -0
  3. data/.github/ISSUE_TEMPLATE/A.md +14 -0
  4. data/.github/ISSUE_TEMPLATE/bug_report.md +47 -0
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
  6. data/.github/PULL_REQUEST_TEMPLATE.md +16 -0
  7. data/.github/support.md +19 -0
  8. data/.github/workflows/tests.yml +53 -0
  9. data/.rubocop.yml +4 -0
  10. data/.rubocop_todo.yml +271 -0
  11. data/CHANGELOG.md +34 -0
  12. data/CONTRIBUTING.md +1 -1
  13. data/Gemfile +9 -0
  14. data/README.md +77 -2
  15. data/bugsnag-api.gemspec +42 -7
  16. data/config/.gitignore +1 -0
  17. data/docker-compose.yml +9 -0
  18. data/dockerfiles/Dockerfile.audit +5 -0
  19. data/lib/bugsnag/api/client.rb +18 -1
  20. data/lib/bugsnag/api/client/collaborators.rb +1 -2
  21. data/lib/bugsnag/api/client/comments.rb +1 -1
  22. data/lib/bugsnag/api/client/currentuser.rb +0 -1
  23. data/lib/bugsnag/api/client/errors.rb +12 -11
  24. data/lib/bugsnag/api/client/eventfields.rb +1 -2
  25. data/lib/bugsnag/api/client/events.rb +1 -2
  26. data/lib/bugsnag/api/client/organizations.rb +1 -2
  27. data/lib/bugsnag/api/client/pivots.rb +1 -2
  28. data/lib/bugsnag/api/client/projects.rb +2 -3
  29. data/lib/bugsnag/api/client/releases.rb +38 -0
  30. data/lib/bugsnag/api/client/stability.rb +16 -0
  31. data/lib/bugsnag/api/client/trends.rb +8 -5
  32. data/lib/bugsnag/api/configuration.rb +1 -1
  33. data/lib/bugsnag/api/error.rb +1 -1
  34. data/lib/bugsnag/api/response/raise_error.rb +0 -2
  35. data/lib/bugsnag/api/version.rb +1 -1
  36. data/scripts/license_finder.sh +4 -0
  37. data/spec/bugsnag/api/client/releases_spec.rb +184 -0
  38. data/spec/bugsnag/api/client/stability_spec.rb +32 -0
  39. data/spec/bugsnag/api/client_spec.rb +69 -7
  40. data/spec/bugsnag/api_spec.rb +2 -0
  41. data/spec/cassettes/Bugsnag_Api_Client/_get/handles_query_params.yml +13 -21
  42. data/spec/cassettes/Bugsnag_Api_Client/_last_response/caches_the_last_agent_response.yml +13 -21
  43. data/spec/cassettes/Bugsnag_Api_Client_Collaborators/_invitecollaborator/creates_and_returns_a_collaborator.yml +14 -26
  44. data/spec/cassettes/Bugsnag_Api_Client_Collaborators/_invitecollaborator/invites_multiple_collaborators.yml +14 -26
  45. data/spec/cassettes/Bugsnag_Api_Client_Collaborators/given_a_collaborator_exists/_collaborator/returns_a_collaborator.yml +29 -53
  46. data/spec/cassettes/Bugsnag_Api_Client_Collaborators/given_a_collaborator_exists/_collaborators/returns_a_list_of_all_organization_collaborators.yml +30 -55
  47. data/spec/cassettes/Bugsnag_Api_Client_Collaborators/given_a_collaborator_exists/_collaborators/returns_a_list_of_all_project_collaborators.yml +30 -55
  48. data/spec/cassettes/Bugsnag_Api_Client_Collaborators/given_a_collaborator_exists/_collaborators/throws_an_argument_error_if_neither_org_id_or_project_id_are_provided.yml +14 -26
  49. data/spec/cassettes/Bugsnag_Api_Client_Collaborators/given_a_collaborator_exists/_delete_collaborator/deletes_a_collaborator.yml +14 -26
  50. data/spec/cassettes/Bugsnag_Api_Client_Collaborators/given_a_collaborator_exists/_update_collaborator_permissions/updates_and_returns_the_collaborator.yml +29 -53
  51. data/spec/cassettes/Bugsnag_Api_Client_Collaborators/given_a_collaborator_exists/_view_collaborator_projects/returns_a_list_of_projects_belonging_to_the_collaborator.yml +49 -55
  52. data/spec/cassettes/Bugsnag_Api_Client_Comments/_create_comment/creates_a_comment_on_the_error.yml +17 -29
  53. data/spec/cassettes/Bugsnag_Api_Client_Comments/given_a_comment_has_been_created/_comment/retrieves_the_comment_specified.yml +32 -56
  54. data/spec/cassettes/Bugsnag_Api_Client_Comments/given_a_comment_has_been_created/_comments/retrieves_all_comments_on_an_error.yml +33 -57
  55. data/spec/cassettes/Bugsnag_Api_Client_Comments/given_a_comment_has_been_created/_delete_comment/deletes_the_comment_and_returns_true.yml +17 -29
  56. data/spec/cassettes/Bugsnag_Api_Client_Comments/given_a_comment_has_been_created/_update_comment/updates_the_message_on_a_comment.yml +32 -56
  57. data/spec/cassettes/Bugsnag_Api_Client_CurrentUser/_list_organizations/when_using_auth_token/returns_the_organization_the_auth_token_belongs_to.yml +14 -27
  58. data/spec/cassettes/Bugsnag_Api_Client_CurrentUser/_list_organizations/when_using_user_credentials/returns_users_organizations.yml +17 -31
  59. data/spec/cassettes/Bugsnag_Api_Client_CurrentUser/_list_projects/when_using_auth_token/lists_current_user_s_projects_in_the_organization.yml +34 -28
  60. data/spec/cassettes/Bugsnag_Api_Client_CurrentUser/_list_projects/when_using_user_credentials/lists_current_user_s_projects_in_the_organization.yml +37 -32
  61. data/spec/cassettes/Bugsnag_Api_Client_Errors/_error/returns_a_single_error.yml +14 -28
  62. data/spec/cassettes/Bugsnag_Api_Client_Errors/_errors/returns_errors_on_the_project.yml +16 -30
  63. data/spec/cassettes/Bugsnag_Api_Client_Errors/_update_errors/updates_and_returns_the_updated_errors.yml +13 -25
  64. data/spec/cassettes/Bugsnag_Api_Client_Events/_error_events/lists_all_error_events.yml +19 -30
  65. data/spec/cassettes/Bugsnag_Api_Client_Events/_event/returns_the_specified_event.yml +16 -199
  66. data/spec/cassettes/Bugsnag_Api_Client_Events/_events/returns_the_a_list_of_project_errors.yml +19 -30
  67. data/spec/cassettes/Bugsnag_Api_Client_Events/_latest_event/returns_the_last_event_on_an_error.yml +16 -199
  68. data/spec/cassettes/Bugsnag_Api_Client_Organizations/_create_organization/creates_a_new_organization.yml +17 -30
  69. data/spec/cassettes/Bugsnag_Api_Client_Organizations/with_organization/_delete_organization/deletes_the_organization.yml +32 -58
  70. data/spec/cassettes/Bugsnag_Api_Client_Organizations/with_organization/_organization/returns_the_requested_organization.yml +35 -61
  71. data/spec/cassettes/Bugsnag_Api_Client_Organizations/with_organization/_update_organization/updates_and_returns_the_organization.yml +35 -61
  72. data/spec/cassettes/Bugsnag_Api_Client_Projects/_create_project/creates_a_new_project.yml +14 -26
  73. data/spec/cassettes/Bugsnag_Api_Client_Projects/given_a_project/_delete_project/deletes_the_project.yml +26 -50
  74. data/spec/cassettes/Bugsnag_Api_Client_Projects/given_a_project/_project/returns_the_requested_project.yml +29 -53
  75. data/spec/cassettes/Bugsnag_Api_Client_Projects/given_a_project/_regenerate_api_key/removes_the_current_api_key_and_replaces_it_with_a_new_api_key.yml +29 -53
  76. data/spec/cassettes/Bugsnag_Api_Client_Projects/given_a_project/_update_project/updates_and_returns_the_project.yml +29 -53
  77. data/spec/cassettes/Bugsnag_Api_Client_Releases/_release/gets_a_single_release.yml +87 -0
  78. data/spec/cassettes/Bugsnag_Api_Client_Releases/_release_groups/accepts_parameters.yml +90 -0
  79. data/spec/cassettes/Bugsnag_Api_Client_Releases/_release_groups/gets_releases_in_a_release_group.yml +87 -0
  80. data/spec/cassettes/Bugsnag_Api_Client_Releases/_releases/accepts_parameters.yml +92 -0
  81. data/spec/cassettes/Bugsnag_Api_Client_Releases/_releases/gets_as_list_of_releases.yml +91 -0
  82. data/spec/cassettes/Bugsnag_Api_Client_Stability/_stability_trend/gets_the_stability_trend.yml +87 -0
  83. data/spec/cassettes/Bugsnag_Api_Client_Trends/_trends_buckets/returns_a_list_of_error_trends_in_bucket_form.yml +14 -26
  84. data/spec/cassettes/Bugsnag_Api_Client_Trends/_trends_buckets/returns_a_list_of_project_trends_in_bucket_form.yml +14 -26
  85. data/spec/cassettes/Bugsnag_Api_Client_Trends/_trends_resolution/returns_a_list_of_project_trends_in_resolution_form.yml +14 -26
  86. data/spec/cassettes/Bugsnag_Api_Client_Trends/_trends_resolution/returns_a_list_of_trends_in_resolution_form.yml +14 -26
  87. data/spec/spec_helper.rb +14 -5
  88. metadata +66 -37
  89. data/.travis.yml +0 -20
@@ -26,7 +26,7 @@ module Bugsnag
26
26
  #
27
27
  # @option filters [Object] An optional filter object, see http://docs.bugsnagapiv2.apiary.io/#introduction/filtering
28
28
  # @option sort [String] Sorting method
29
- # @option base [String] Only Events occuring before this time will be used
29
+ # @option base [String] Only Events occuring before this time will be used
30
30
  # @return [Array<Sawyer::Resource>] List of values for the Pivots requested
31
31
  # @see http://docs.bugsnagapiv2.apiary.io/#reference/errors/pivots/list-values-of-a-pivot-on-an-error
32
32
  def pivot_values(project_id, ef_display_id, error_id=nil, options = {})
@@ -40,4 +40,3 @@ module Bugsnag
40
40
  end
41
41
  end
42
42
  end
43
-
@@ -42,7 +42,7 @@ module Bugsnag
42
42
 
43
43
  # Regenerate a Project's notifier API key
44
44
  #
45
- # @return
45
+ # @return
46
46
  # @see http://docs.bugsnagapiv2.apiary.io/#reference/projects/projects/regenerate-a-project's-notifier-api-key
47
47
  def regenerate_api_key(id, options = {})
48
48
  delete "projects/#{id}/api_key", options
@@ -50,7 +50,7 @@ module Bugsnag
50
50
 
51
51
  # Delete a Project
52
52
  #
53
- # @return
53
+ # @return
54
54
  # @see http://docs.bugsnagapiv2.apiary.io/#reference/organizations/organizations/delete-an-organization
55
55
  def delete_project(id, options = {})
56
56
  boolean_from_response :delete, "projects/#{id}", options
@@ -59,4 +59,3 @@ module Bugsnag
59
59
  end
60
60
  end
61
61
  end
62
-
@@ -0,0 +1,38 @@
1
+ module Bugsnag
2
+ module Api
3
+ class Client
4
+ # Methods for the Releases API
5
+ module Releases
6
+ # List the Releases in a Project
7
+ #
8
+ # @option release_stage [String] Only Releases with this release stage will be returned
9
+ # @option base [String] Only Releases created before this time will be returned
10
+ # @option sort [String] How to sort the results, one of: timestamp, percent_of_sessions
11
+ # @option offset [Number] The pagination offset
12
+ # @option per_page [Number] The number of results to return per page
13
+ # @return [Array<Sawyer::Resource>] List of Events for the specified Error
14
+ # @see https://bugsnagapiv2.docs.apiary.io/#reference/projects/releases/list-releases-on-a-project
15
+ def releases(project_id, options = {})
16
+ get "projects/#{project_id}/releases", options
17
+ end
18
+
19
+ # View a single Release
20
+ #
21
+ # @see https://bugsnagapiv2.docs.apiary.io/#reference/projects/releases/view-a-release
22
+ def release(project_id, release_id, options = {})
23
+ get "projects/#{project_id}/releases/#{release_id}", options
24
+ end
25
+
26
+ # List the Releases in a Release Group
27
+ #
28
+ # @option per_page [Number] The number of results to return per page
29
+ # @option page_token [String] Value from the next relation in the Link response header to obtain the next page of results
30
+ # @return [Array<Sawyer::Resource>] List of Releases for the specified Release Group
31
+ # @see https://bugsnagapiv2.docs.apiary.io/#reference/projects/releases/list-releases-on-a-release-group
32
+ def releases_in_group(release_group_id, options = {})
33
+ get "release_groups/#{release_group_id}/releases", options
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,16 @@
1
+ module Bugsnag
2
+ module Api
3
+ class Client
4
+ # Methods for the Stability API
5
+ module Stability
6
+ # View the stability trend for a project
7
+ #
8
+ # @return [Sawyer::Resource] Stability trend
9
+ # @see https://bugsnagapiv2.docs.apiary.io/#reference/projects/stability-trend/view-the-stability-trend-for-a-project
10
+ def stability_trend(id, options = {})
11
+ get "projects/#{id}/stability_trend", options
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -12,10 +12,12 @@ module Bugsnag
12
12
  # @return [Array<Sawyer::Resource>] List of Trends as requested
13
13
  # @see http://docs.bugsnagapiv2.apiary.io/#reference/errors/trends/list-the-trends-for-an-error-(buckets)
14
14
  def trends_buckets(project_id, buckets_count, error_id=nil, options = {})
15
+ defaults = {:query => {:buckets_count => buckets_count}}
16
+ merged_opts = deep_merge(defaults, options)
15
17
  if !error_id.nil?
16
- get "projects/#{project_id}/errors/#{error_id}/trend", options.merge({:query => {:buckets_count => buckets_count}})
18
+ get "projects/#{project_id}/errors/#{error_id}/trend", merged_opts
17
19
  else
18
- get "projects/#{project_id}/trend", options.merge({:query => {:buckets_count => buckets_count}})
20
+ get "projects/#{project_id}/trend", merged_opts
19
21
  end
20
22
  end
21
23
 
@@ -25,14 +27,15 @@ module Bugsnag
25
27
  # @return [Array<Sawyer::Resource>] List of Trends as requested
26
28
  # @see http://docs.bugsnagapiv2.apiary.io/#reference/errors/trends/list-the-trends-for-an-error-(buckets)
27
29
  def trends_resolution(project_id, resolution, error_id=nil, options = {})
30
+ defaults = {:query => {:resolution => resolution}}
31
+ merged_opts = deep_merge(defaults, options)
28
32
  if !error_id.nil?
29
- get "projects/#{project_id}/errors/#{error_id}/trend", options.merge({:query => {:resolution => resolution}})
33
+ get "projects/#{project_id}/errors/#{error_id}/trend", merged_opts
30
34
  else
31
- get "projects/#{project_id}/trend", options.merge({:query => {:resolution => resolution}})
35
+ get "projects/#{project_id}/trend", merged_opts
32
36
  end
33
37
  end
34
38
  end
35
39
  end
36
40
  end
37
41
  end
38
-
@@ -45,7 +45,7 @@ module Bugsnag
45
45
 
46
46
  # Load configuration from hash
47
47
  def load(options = {})
48
- options.each {|k,v| self.send("#{k}=", v) if self.respond_to?("#{k}=") && !v.nil?}
48
+ options.each { |k,v| self.send("#{k}=", v) if self.respond_to?("#{k}=") && !v.nil?}
49
49
  end
50
50
  end
51
51
  end
@@ -3,7 +3,7 @@ module Bugsnag
3
3
  # Custom error class for rescuing from all Bugsnag API errors
4
4
  class Error < StandardError
5
5
 
6
- # Returns the appropriate Bugnsag::Api::Error subclass based
6
+ # Returns the appropriate Bugsnag::Api::Error subclass based
7
7
  # on status and response message
8
8
  #
9
9
  # @param [Hash] response HTTP response
@@ -9,8 +9,6 @@ module Bugsnag
9
9
  # This class raises an Bugsnag-flavored exception based
10
10
  # HTTP status codes returned by the API
11
11
  class RaiseError < Faraday::Response::Middleware
12
-
13
- private
14
12
  def on_complete(response)
15
13
  if error = Bugsnag::Api::Error.from_response(response)
16
14
  raise error
@@ -1,5 +1,5 @@
1
1
  module Bugsnag
2
2
  module Api
3
- VERSION = "2.0.0"
3
+ VERSION = "2.1.0"
4
4
  end
5
5
  end
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+ curl https://raw.githubusercontent.com/bugsnag/license-audit/master/config/decision_files/global.yml -o config/global.yml
3
+ bundle install
4
+ license_finder --decisions-file=config/global.yml
@@ -0,0 +1,184 @@
1
+ require "spec_helper"
2
+
3
+ describe Bugsnag::Api::Client::Releases do
4
+ before do
5
+ @client = auth_token_client
6
+ @project_id = test_bugsnag_project_id
7
+ @release_id = test_bugsnag_release_id
8
+ @release_group_id = test_bugsnag_release_group_id
9
+
10
+ Bugsnag::Api.reset!
11
+ end
12
+
13
+ describe ".releases", :vcr do
14
+ it "gets as list of releases" do
15
+ releases = @client.releases(@project_id)
16
+
17
+ expect(releases).to be_an_instance_of(Array)
18
+
19
+ releases.map!(&:to_h)
20
+
21
+ expect(releases.first[:id]).to eq(@release_id)
22
+ expect(releases.first[:project_id]).to eq(@project_id)
23
+ expect(releases.first[:release_group_id]).to eq(@release_group_id)
24
+
25
+ expect(releases).to all have_key(:id)
26
+ expect(releases).to all have_key(:project_id)
27
+ expect(releases).to all have_key(:release_group_id)
28
+ expect(releases).to all have_key(:release_time)
29
+ expect(releases).to all have_key(:release_source)
30
+ expect(releases).to all have_key(:app_version)
31
+ expect(releases).to all have_key(:app_version_code)
32
+ expect(releases).to all have_key(:app_bundle_version)
33
+ expect(releases).to all have_key(:build_label)
34
+ expect(releases).to all have_key(:builder_name)
35
+ expect(releases).to all have_key(:build_tool)
36
+ expect(releases).to all have_key(:errors_introduced_count)
37
+ expect(releases).to all have_key(:errors_seen_count)
38
+ expect(releases).to all have_key(:sessions_count_in_last_24h)
39
+ expect(releases).to all have_key(:total_sessions_count)
40
+ expect(releases).to all have_key(:unhandled_sessions_count)
41
+ expect(releases).to all have_key(:accumulative_daily_users_seen)
42
+ expect(releases).to all have_key(:accumulative_daily_users_with_unhandled)
43
+ expect(releases).to all have_key(:metadata)
44
+ expect(releases).to all have_key(:release_stage)
45
+ end
46
+
47
+ it "accepts parameters" do
48
+ releases = @client.releases(
49
+ @project_id,
50
+ {
51
+ release_stage: 'development',
52
+ base: '2021-07-21T12:00:00Z',
53
+ sort: 'percent_of_sessions',
54
+ offset: 0,
55
+ per_page: 1
56
+ }
57
+ )
58
+
59
+ expect(releases).to be_an_instance_of(Array)
60
+
61
+ releases.map!(&:to_h)
62
+
63
+ expect(releases.first[:id]).to eq(@release_id)
64
+ expect(releases.first[:project_id]).to eq(@project_id)
65
+ expect(releases.first[:release_group_id]).to eq(@release_group_id)
66
+
67
+ expect(releases).to all have_key(:id)
68
+ expect(releases).to all have_key(:project_id)
69
+ expect(releases).to all have_key(:release_group_id)
70
+ expect(releases).to all have_key(:release_time)
71
+ expect(releases).to all have_key(:release_source)
72
+ expect(releases).to all have_key(:app_version)
73
+ expect(releases).to all have_key(:app_version_code)
74
+ expect(releases).to all have_key(:app_bundle_version)
75
+ expect(releases).to all have_key(:build_label)
76
+ expect(releases).to all have_key(:builder_name)
77
+ expect(releases).to all have_key(:build_tool)
78
+ expect(releases).to all have_key(:errors_introduced_count)
79
+ expect(releases).to all have_key(:errors_seen_count)
80
+ expect(releases).to all have_key(:sessions_count_in_last_24h)
81
+ expect(releases).to all have_key(:total_sessions_count)
82
+ expect(releases).to all have_key(:unhandled_sessions_count)
83
+ expect(releases).to all have_key(:accumulative_daily_users_seen)
84
+ expect(releases).to all have_key(:accumulative_daily_users_with_unhandled)
85
+ expect(releases).to all have_key(:metadata)
86
+ expect(releases).to all have_key(:release_stage)
87
+ end
88
+ end
89
+
90
+ describe ".release", :vcr do
91
+ it "gets a single release" do
92
+ release = @client.release(@project_id, @release_id)
93
+
94
+ expect(release.id).to eq(@release_id)
95
+ expect(release.project_id).to eq(@project_id)
96
+ expect(release.release_group_id).to eq(@release_group_id)
97
+ expect(release.release_time).not_to be_nil
98
+ expect(release.release_source).not_to be_nil
99
+ expect(release.app_version).not_to be_nil
100
+ expect(release.app_version_code).not_to be_nil
101
+ expect(release.app_bundle_version).not_to be_nil
102
+ expect(release.build_label).not_to be_nil
103
+ expect(release.builder_name).not_to be_nil
104
+ expect(release.build_tool).not_to be_nil
105
+ expect(release.errors_introduced_count).not_to be_nil
106
+ expect(release.errors_seen_count).not_to be_nil
107
+ expect(release.sessions_count_in_last_24h).not_to be_nil
108
+ expect(release.total_sessions_count).not_to be_nil
109
+ expect(release.unhandled_sessions_count).not_to be_nil
110
+ expect(release.accumulative_daily_users_seen).not_to be_nil
111
+ expect(release.accumulative_daily_users_with_unhandled).not_to be_nil
112
+ expect(release.metadata).not_to be_nil
113
+ expect(release.release_stage).not_to be_nil
114
+ end
115
+ end
116
+
117
+ describe ".release_groups", :vcr do
118
+ it "gets releases in a release group" do
119
+ releases = @client.releases_in_group(@release_group_id)
120
+
121
+ expect(releases).to be_an_instance_of(Array)
122
+
123
+ releases.map!(&:to_h)
124
+
125
+ expect(releases.first[:id]).to eq(@release_id)
126
+ expect(releases.first[:project_id]).to eq(@project_id)
127
+ expect(releases.first[:release_group_id]).to eq(@release_group_id)
128
+
129
+ expect(releases).to all have_key(:id)
130
+ expect(releases).to all have_key(:project_id)
131
+ expect(releases).to all have_key(:release_group_id)
132
+ expect(releases).to all have_key(:release_time)
133
+ expect(releases).to all have_key(:release_source)
134
+ expect(releases).to all have_key(:app_version)
135
+ expect(releases).to all have_key(:app_version_code)
136
+ expect(releases).to all have_key(:app_bundle_version)
137
+ expect(releases).to all have_key(:build_label)
138
+ expect(releases).to all have_key(:builder_name)
139
+ expect(releases).to all have_key(:build_tool)
140
+ expect(releases).to all have_key(:errors_introduced_count)
141
+ expect(releases).to all have_key(:errors_seen_count)
142
+ expect(releases).to all have_key(:sessions_count_in_last_24h)
143
+ expect(releases).to all have_key(:total_sessions_count)
144
+ expect(releases).to all have_key(:unhandled_sessions_count)
145
+ expect(releases).to all have_key(:accumulative_daily_users_seen)
146
+ expect(releases).to all have_key(:accumulative_daily_users_with_unhandled)
147
+ expect(releases).to all have_key(:metadata)
148
+ expect(releases).to all have_key(:release_stage)
149
+ end
150
+
151
+ it "accepts parameters" do
152
+ releases = @client.releases_in_group(@release_group_id, { per_page: 1 })
153
+
154
+ expect(releases).to be_an_instance_of(Array)
155
+
156
+ releases.map!(&:to_h)
157
+
158
+ expect(releases.first[:id]).to eq(@release_id)
159
+ expect(releases.first[:project_id]).to eq(@project_id)
160
+ expect(releases.first[:release_group_id]).to eq(@release_group_id)
161
+
162
+ expect(releases).to all have_key(:id)
163
+ expect(releases).to all have_key(:project_id)
164
+ expect(releases).to all have_key(:release_group_id)
165
+ expect(releases).to all have_key(:release_time)
166
+ expect(releases).to all have_key(:release_source)
167
+ expect(releases).to all have_key(:app_version)
168
+ expect(releases).to all have_key(:app_version_code)
169
+ expect(releases).to all have_key(:app_bundle_version)
170
+ expect(releases).to all have_key(:build_label)
171
+ expect(releases).to all have_key(:builder_name)
172
+ expect(releases).to all have_key(:build_tool)
173
+ expect(releases).to all have_key(:errors_introduced_count)
174
+ expect(releases).to all have_key(:errors_seen_count)
175
+ expect(releases).to all have_key(:sessions_count_in_last_24h)
176
+ expect(releases).to all have_key(:total_sessions_count)
177
+ expect(releases).to all have_key(:unhandled_sessions_count)
178
+ expect(releases).to all have_key(:accumulative_daily_users_seen)
179
+ expect(releases).to all have_key(:accumulative_daily_users_with_unhandled)
180
+ expect(releases).to all have_key(:metadata)
181
+ expect(releases).to all have_key(:release_stage)
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,32 @@
1
+ require "spec_helper"
2
+
3
+ describe Bugsnag::Api::Client::Stability do
4
+ before do
5
+ @client = auth_token_client
6
+ @project_id = test_bugsnag_project_id
7
+
8
+ Bugsnag::Api.reset!
9
+ end
10
+
11
+ describe ".stability_trend", :vcr do
12
+ it "gets the stability trend" do
13
+ stability_trend = @client.stability_trend(@project_id)
14
+
15
+ expect(stability_trend.project_id).to eq(@project_id)
16
+ expect(stability_trend.release_stage_name).not_to be_nil
17
+ expect(stability_trend.timeline_points).to be_an_instance_of(Array)
18
+
19
+ # convert each "Sawyer::Resource" to a hash so we can use the "have_key" matcher
20
+ timeline_points = stability_trend.timeline_points.map(&:to_h)
21
+
22
+ expect(timeline_points).to all have_key(:bucket_start)
23
+ expect(timeline_points).to all have_key(:bucket_end)
24
+ expect(timeline_points).to all have_key(:total_sessions_count)
25
+ expect(timeline_points).to all have_key(:unhandled_sessions_count)
26
+ expect(timeline_points).to all have_key(:users_seen)
27
+ expect(timeline_points).to all have_key(:users_with_unhandled)
28
+
29
+ assert_requested(:get, bugsnag_url("/projects/#{@project_id}/stability_trend"))
30
+ end
31
+ end
32
+ end
@@ -1,3 +1,4 @@
1
+ require "spec_helper"
1
2
  require "json"
2
3
 
3
4
  describe Bugsnag::Api::Client do
@@ -45,7 +46,7 @@ describe Bugsnag::Api::Client do
45
46
 
46
47
  it "handles query params", :vcr do
47
48
  Bugsnag::Api.get bugsnag_url("/"), :foo => "bar"
48
- assert_requested :get, "https://api.bugsnag.com?foo=bar"
49
+ assert_requested :get, bugsnag_url("?foo=bar")
49
50
  end
50
51
 
51
52
  it "handles headers" do
@@ -81,20 +82,81 @@ describe Bugsnag::Api::Client do
81
82
  end
82
83
  end
83
84
 
85
+ describe ".deep_merge" do
86
+ it "returns a merged hash" do
87
+ client = Bugsnag::Api::Client.new(:auth_token => "example")
88
+ lhs = {
89
+ :foo => "foo"
90
+ }
91
+ rhs = {
92
+ :bar => "bar"
93
+ }
94
+ merged = client.deep_merge(lhs, rhs)
95
+ expect(merged).to_not eq(lhs)
96
+ expect(merged).to_not eq(rhs)
97
+ expect(merged).to eq({
98
+ :foo => "foo",
99
+ :bar => "bar"
100
+ })
101
+ end
102
+
103
+ it "favors rhs over lhs" do
104
+ client = Bugsnag::Api::Client.new(:auth_token => "example")
105
+ lhs = {
106
+ :foo => "foo"
107
+ }
108
+ rhs = {
109
+ :foo => "bar"
110
+ }
111
+ merged = client.deep_merge(lhs, rhs)
112
+ expect(merged).to eq({:foo => "bar"})
113
+ end
114
+
115
+ it "recursively merges hashes" do
116
+ client = Bugsnag::Api::Client.new(:auth_token => "example")
117
+ lhs = {
118
+ :foo => {
119
+ :bar => "bar"
120
+ }
121
+ }
122
+ rhs = {
123
+ :foo => {
124
+ :foobar => "foobar"
125
+ }
126
+ }
127
+ merged = client.deep_merge(lhs, rhs)
128
+ expect(merged).to eq(
129
+ {:foo => {
130
+ :bar => "bar",
131
+ :foobar => "foobar"
132
+ }
133
+ })
134
+ end
135
+ end
136
+
84
137
  context "error handling" do
138
+
139
+ before do
140
+ VCR.turn_off!
141
+ end
142
+
143
+ after do
144
+ VCR.turn_on!
145
+ end
146
+
85
147
  it "raises on 404" do
86
148
  stub_get('/booya').to_return(:status => 404)
87
- expect { Bugsnag::Api.get('/booya') }.to raise_error(Bugsnag::Api::NotFound)
149
+ expect { Bugsnag::Api.get(bugsnag_url('/booya')) }.to raise_error(Bugsnag::Api::NotFound)
88
150
  end
89
151
 
90
152
  it "raises on 429" do
91
153
  stub_get('/test').to_return(:status => 429)
92
- expect { Bugsnag::Api.get('/test') }.to raise_error(Bugsnag::Api::RateLimitExceeded)
154
+ expect { Bugsnag::Api.get(bugsnag_url('/test')) }.to raise_error(Bugsnag::Api::RateLimitExceeded)
93
155
  end
94
156
 
95
157
  it "raises on 500" do
96
158
  stub_get('/boom').to_return(:status => 500)
97
- expect { Bugsnag::Api.get('/boom') }.to raise_error(Bugsnag::Api::InternalServerError)
159
+ expect { Bugsnag::Api.get(bugsnag_url('/boom')) }.to raise_error(Bugsnag::Api::InternalServerError)
98
160
  end
99
161
 
100
162
  it "includes an error" do
@@ -106,7 +168,7 @@ describe Bugsnag::Api::Client do
106
168
  },
107
169
  :body => {:error => "Comments must contain a message"}.to_json
108
170
  begin
109
- Bugsnag::Api.get('/boom')
171
+ Bugsnag::Api.get(bugsnag_url('/boom'))
110
172
  rescue Bugsnag::Api::UnprocessableEntity => e
111
173
  expect(e.message).to include("Error: Comments must contain a message")
112
174
  end
@@ -119,7 +181,7 @@ describe Bugsnag::Api::Client do
119
181
  :content_type => "application/json",
120
182
  },
121
183
  :body => {:message => "I'm a teapot"}.to_json
122
- expect { Bugsnag::Api.get('/user') }.to raise_error(Bugsnag::Api::ClientError)
184
+ expect { Bugsnag::Api.get(bugsnag_url('/user')) }.to raise_error(Bugsnag::Api::ClientError)
123
185
  end
124
186
 
125
187
  it "raises on unknown server errors" do
@@ -129,7 +191,7 @@ describe Bugsnag::Api::Client do
129
191
  :content_type => "application/json",
130
192
  },
131
193
  :body => {:message => "Bandwidth exceeded"}.to_json
132
- expect { Bugsnag::Api.get('/user') }.to raise_error(Bugsnag::Api::ServerError)
194
+ expect { Bugsnag::Api.get(bugsnag_url('/user')) }.to raise_error(Bugsnag::Api::ServerError)
133
195
  end
134
196
  end
135
197
  end