pact_broker 2.105.0 → 2.107.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (178) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +57 -1
  3. data/Gemfile +3 -0
  4. data/README.md +1 -1
  5. data/db/migrations/20221130_add_provider_version_id_index_to_verifications.rb +28 -0
  6. data/db/migrations/20221208_add_index_to_pact_version_provider_tag_successful_verifications.rb +21 -0
  7. data/db/migrations/20221215_add_prov_ver_id_ndx_to_latest_verifi_id_for_pact_ver_and_prov_ver.rb +21 -0
  8. data/db/migrations/20230131_add_cons_ver_id_ndx_to_latest_pp_id_for_cons_ver.rb +21 -0
  9. data/db/migrations/20230216_add_branch_heads_branch_version_id_index.rb +21 -0
  10. data/db/migrations/20230428_add_index_for_webhook_executions_pact_publication_id.rb +17 -0
  11. data/docs/CONFIGURATION.md +1 -1
  12. data/docs/api/PAGINATION.md +43 -0
  13. data/lib/pact_broker/api/contracts/base_contract.rb +22 -7
  14. data/lib/pact_broker/api/contracts/can_i_deploy_query_schema.rb +34 -0
  15. data/lib/pact_broker/api/contracts/configuration.rb +2 -0
  16. data/lib/pact_broker/api/contracts/consumer_version_selector_contract.rb +140 -0
  17. data/lib/pact_broker/api/contracts/dry_validation_errors_formatter.rb +50 -0
  18. data/lib/pact_broker/api/contracts/dry_validation_macros.rb +79 -0
  19. data/lib/pact_broker/api/contracts/dry_validation_methods.rb +71 -0
  20. data/lib/pact_broker/api/contracts/environment_schema.rb +19 -33
  21. data/lib/pact_broker/api/contracts/pacticipant_create_schema.rb +4 -17
  22. data/lib/pact_broker/api/contracts/pacticipant_schema.rb +15 -24
  23. data/lib/pact_broker/api/contracts/pacts_for_verification_json_query_schema.rb +37 -146
  24. data/lib/pact_broker/api/contracts/pacts_for_verification_query_string_schema.rb +7 -20
  25. data/lib/pact_broker/api/contracts/publish_contracts_contract_contract.rb +62 -0
  26. data/lib/pact_broker/api/contracts/publish_contracts_schema.rb +25 -112
  27. data/lib/pact_broker/api/contracts/put_pact_params_contract.rb +21 -26
  28. data/lib/pact_broker/api/contracts/utf_8_validation.rb +19 -0
  29. data/lib/pact_broker/api/contracts/validation_helpers.rb +71 -0
  30. data/lib/pact_broker/api/contracts/verification_contract.rb +10 -29
  31. data/lib/pact_broker/api/contracts/webhook_contract.rb +20 -170
  32. data/lib/pact_broker/api/contracts/webhook_pacticipant_contract.rb +33 -0
  33. data/lib/pact_broker/api/contracts/webhook_request_contract.rb +125 -0
  34. data/lib/pact_broker/api/contracts.rb +3 -0
  35. data/lib/pact_broker/api/decorators/custom_error_problem_json_decorator.rb +36 -0
  36. data/lib/pact_broker/api/decorators/dashboard_text_decorator.rb +2 -2
  37. data/lib/pact_broker/api/decorators/extended_pact_decorator.rb +1 -1
  38. data/lib/pact_broker/api/decorators/matrix_decorator.rb +4 -4
  39. data/lib/pact_broker/api/decorators/matrix_text_decorator.rb +1 -1
  40. data/lib/pact_broker/api/decorators/pact_decorator.rb +1 -1
  41. data/lib/pact_broker/api/decorators/pacticipant_collection_decorator.rb +5 -2
  42. data/lib/pact_broker/api/decorators/pacticipant_decorator.rb +2 -1
  43. data/lib/pact_broker/api/decorators/pacts_for_verification_query_decorator.rb +4 -1
  44. data/lib/pact_broker/api/decorators/pagination_links.rb +11 -0
  45. data/lib/pact_broker/api/decorators/runtime_error_problem_json_decorator.rb +34 -0
  46. data/lib/pact_broker/api/decorators/validation_errors_problem_json_decorator.rb +66 -0
  47. data/lib/pact_broker/api/decorators/verifiable_pact_decorator.rb +4 -4
  48. data/lib/pact_broker/api/decorators/webhook_decorator.rb +2 -3
  49. data/lib/pact_broker/api/decorators/webhook_execution_result_decorator.rb +5 -12
  50. data/lib/pact_broker/api/resources/all_webhooks.rb +5 -11
  51. data/lib/pact_broker/api/resources/badge_methods.rb +1 -1
  52. data/lib/pact_broker/api/resources/base_resource.rb +31 -68
  53. data/lib/pact_broker/api/resources/branch_version.rb +3 -3
  54. data/lib/pact_broker/api/resources/can_i_deploy.rb +4 -19
  55. data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_branch_to_environment.rb +1 -4
  56. data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_tag_to_tag.rb +0 -2
  57. data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_tag_to_tag_badge.rb +1 -2
  58. data/lib/pact_broker/api/resources/currently_deployed_versions_for_environment.rb +2 -2
  59. data/lib/pact_broker/api/resources/currently_supported_versions_for_environment.rb +2 -2
  60. data/lib/pact_broker/api/resources/dashboard.rb +3 -3
  61. data/lib/pact_broker/api/resources/deployed_version.rb +1 -1
  62. data/lib/pact_broker/api/resources/deployed_versions_for_version_and_environment.rb +2 -2
  63. data/lib/pact_broker/api/resources/environment.rb +1 -1
  64. data/lib/pact_broker/api/resources/environments.rb +2 -2
  65. data/lib/pact_broker/api/resources/error_handling_methods.rb +57 -0
  66. data/lib/pact_broker/api/resources/error_response_generator.rb +70 -0
  67. data/lib/pact_broker/api/resources/integrations.rb +1 -1
  68. data/lib/pact_broker/api/resources/label.rb +1 -1
  69. data/lib/pact_broker/api/resources/latest_pact.rb +2 -2
  70. data/lib/pact_broker/api/resources/latest_pacts.rb +1 -1
  71. data/lib/pact_broker/api/resources/latest_verifications_for_consumer_version.rb +2 -2
  72. data/lib/pact_broker/api/resources/matrix.rb +2 -2
  73. data/lib/pact_broker/api/resources/matrix_for_consumer_and_provider.rb +1 -1
  74. data/lib/pact_broker/api/resources/pact.rb +7 -4
  75. data/lib/pact_broker/api/resources/pact_triggered_webhooks.rb +1 -1
  76. data/lib/pact_broker/api/resources/pact_version.rb +1 -1
  77. data/lib/pact_broker/api/resources/pact_versions.rb +1 -1
  78. data/lib/pact_broker/api/resources/pact_webhooks.rb +7 -14
  79. data/lib/pact_broker/api/resources/pact_webhooks_status.rb +6 -2
  80. data/lib/pact_broker/api/resources/pacticipant.rb +1 -1
  81. data/lib/pact_broker/api/resources/pacticipant_webhooks.rb +7 -5
  82. data/lib/pact_broker/api/resources/pacticipants.rb +6 -3
  83. data/lib/pact_broker/api/resources/pacticipants_for_label.rb +1 -1
  84. data/lib/pact_broker/api/resources/pagination_methods.rb +8 -4
  85. data/lib/pact_broker/api/resources/previous_distinct_pact_version.rb +1 -1
  86. data/lib/pact_broker/api/resources/provider_pacts.rb +1 -1
  87. data/lib/pact_broker/api/resources/provider_pacts_for_verification.rb +4 -13
  88. data/lib/pact_broker/api/resources/publish_contracts.rb +8 -3
  89. data/lib/pact_broker/api/resources/released_version.rb +1 -1
  90. data/lib/pact_broker/api/resources/released_versions_for_version_and_environment.rb +2 -2
  91. data/lib/pact_broker/api/resources/tag.rb +1 -1
  92. data/lib/pact_broker/api/resources/tagged_pact_versions.rb +1 -1
  93. data/lib/pact_broker/api/resources/triggered_webhook_logs.rb +2 -2
  94. data/lib/pact_broker/api/resources/verification.rb +2 -2
  95. data/lib/pact_broker/api/resources/verification_triggered_webhooks.rb +1 -1
  96. data/lib/pact_broker/api/resources/verifications.rb +4 -6
  97. data/lib/pact_broker/api/resources/version.rb +1 -1
  98. data/lib/pact_broker/api/resources/versions.rb +6 -13
  99. data/lib/pact_broker/api/resources/webhook.rb +7 -6
  100. data/lib/pact_broker/api/resources/webhook_execution.rb +6 -4
  101. data/lib/pact_broker/api.rb +3 -13
  102. data/lib/pact_broker/app.rb +0 -2
  103. data/lib/pact_broker/application_context.rb +4 -4
  104. data/lib/pact_broker/certificates/certificate.rb +1 -0
  105. data/lib/pact_broker/config/setting.rb +1 -0
  106. data/lib/pact_broker/contracts/service.rb +1 -0
  107. data/lib/pact_broker/date_helper.rb +1 -1
  108. data/lib/pact_broker/db/clean_incremental.rb +67 -59
  109. data/lib/pact_broker/db/delete_overwritten_data.rb +6 -2
  110. data/lib/pact_broker/deployments/currently_deployed_version_id.rb +2 -0
  111. data/lib/pact_broker/deployments/deployed_version.rb +2 -0
  112. data/lib/pact_broker/deployments/deployed_version_service.rb +5 -1
  113. data/lib/pact_broker/deployments/environment.rb +2 -0
  114. data/lib/pact_broker/deployments/environment_service.rb +4 -3
  115. data/lib/pact_broker/deployments/released_version.rb +2 -0
  116. data/lib/pact_broker/deployments/released_version_service.rb +4 -0
  117. data/lib/pact_broker/diagnostic/resources/base_resource.rb +1 -1
  118. data/lib/pact_broker/doc/views/index/publish-contracts.markdown +5 -5
  119. data/lib/pact_broker/domain/label.rb +1 -0
  120. data/lib/pact_broker/domain/tag.rb +2 -0
  121. data/lib/pact_broker/domain/verification.rb +1 -1
  122. data/lib/pact_broker/domain/version.rb +4 -1
  123. data/lib/pact_broker/domain/webhook.rb +1 -1
  124. data/lib/pact_broker/index/service.rb +2 -2
  125. data/lib/pact_broker/integrations/integration.rb +1 -0
  126. data/lib/pact_broker/locale/en.yml +36 -14
  127. data/lib/pact_broker/matrix/query_ids.rb +4 -4
  128. data/lib/pact_broker/matrix/resolved_selector.rb +6 -1
  129. data/lib/pact_broker/matrix/service.rb +1 -0
  130. data/lib/pact_broker/messages.rb +5 -1
  131. data/lib/pact_broker/pacticipants/repository.rb +16 -14
  132. data/lib/pact_broker/pacticipants/service.rb +11 -8
  133. data/lib/pact_broker/pacts/pact_params.rb +6 -17
  134. data/lib/pact_broker/pacts/pact_version.rb +1 -0
  135. data/lib/pact_broker/pacts/selected_pact.rb +4 -0
  136. data/lib/pact_broker/policies.rb +4 -4
  137. data/lib/pact_broker/repositories/helpers.rb +11 -0
  138. data/lib/pact_broker/repositories/page.rb +24 -0
  139. data/lib/pact_broker/string_refinements.rb +4 -0
  140. data/lib/pact_broker/tasks/clean_task.rb +7 -3
  141. data/lib/pact_broker/test/http_test_data_builder.rb +46 -2
  142. data/lib/pact_broker/ui/app.rb +2 -2
  143. data/lib/pact_broker/ui/views/matrix/show.haml +1 -1
  144. data/lib/pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version.rb +1 -1
  145. data/lib/pact_broker/verifications/pact_version_provider_tag_successful_verification.rb +1 -0
  146. data/lib/pact_broker/verifications/repository.rb +14 -11
  147. data/lib/pact_broker/verifications/service.rb +0 -6
  148. data/lib/pact_broker/version.rb +1 -1
  149. data/lib/pact_broker/versions/branch.rb +1 -0
  150. data/lib/pact_broker/versions/branch_head.rb +2 -1
  151. data/lib/pact_broker/versions/branch_version.rb +11 -0
  152. data/lib/pact_broker/versions/repository.rb +12 -0
  153. data/lib/pact_broker/versions/service.rb +4 -0
  154. data/lib/pact_broker/webhooks/execution.rb +1 -1
  155. data/lib/pact_broker/webhooks/repository.rb +1 -1
  156. data/lib/pact_broker/webhooks/service.rb +3 -25
  157. data/lib/pact_broker/webhooks/triggered_webhook.rb +1 -0
  158. data/lib/pact_broker/webhooks/webhook_event.rb +1 -0
  159. data/lib/pact_broker/webmachine.rb +22 -0
  160. data/lib/rack/pact_broker/invalid_uri_protection.rb +1 -1
  161. data/lib/rack/pact_broker/request_target.rb +1 -1
  162. data/lib/rack/pact_broker/use_when.rb +6 -5
  163. data/lib/sequel/plugins/age.rb +13 -0
  164. data/lib/webmachine/application_monkey_patch.rb +15 -0
  165. data/lib/webmachine/describe_routes.rb +35 -8
  166. data/lib/webmachine/render_error_monkey_patch.rb +70 -0
  167. data/pact_broker.gemspec +7 -18
  168. metadata +72 -76
  169. data/lib/pact/doc/README.md +0 -5
  170. data/lib/pact_broker/api/contracts/dry_validation_predicates.rb +0 -36
  171. data/lib/pact_broker/api/contracts/dry_validation_workarounds.rb +0 -39
  172. data/lib/pact_broker/api/contracts/pacticipant_name_contract.rb +0 -24
  173. data/lib/pact_broker/api/contracts/pacticipant_name_validation.rb +0 -30
  174. data/lib/pact_broker/api/contracts/request_validations.rb +0 -33
  175. data/lib/pact_broker/api/resources/error_response_body_generator.rb +0 -41
  176. data/lib/pact_broker/api/resources/webhook_resource_methods.rb +0 -17
  177. data/lib/pact_broker/matrix/can_i_deploy_query_schema.rb +0 -46
  178. data/lib/rack/pact_broker/convert_404_to_hal.rb +0 -20
@@ -10,6 +10,8 @@ require "pact_broker/pacts/pact_params"
10
10
  require "pact_broker/api/resources/authentication"
11
11
  require "pact_broker/api/resources/authorization"
12
12
  require "pact_broker/errors"
13
+ require "pact_broker/api/resources/error_handling_methods"
14
+ require "pact_broker/api/contracts/utf_8_validation"
13
15
 
14
16
  module PactBroker
15
17
  module Api
@@ -22,6 +24,8 @@ module PactBroker
22
24
  include PactBroker::Api::PactBrokerUrls
23
25
  include PactBroker::Api::Resources::Authentication
24
26
  include PactBroker::Api::Resources::Authorization
27
+ include PactBroker::Api::Resources::ErrorHandlingMethods
28
+ include PactBroker::Api::Contracts::UTF8Validation
25
29
 
26
30
  include PactBroker::Logging
27
31
 
@@ -63,12 +67,11 @@ module PactBroker
63
67
  end
64
68
  end
65
69
 
66
- # The path_info segments aren't URL decoded
70
+ # Remove the non-path compontents in the path_info (eg. the application context, which is naughtily passed in via the path_info)
67
71
  def identifier_from_path
68
72
  @identifier_from_path ||= request.path_info.each_with_object({}) do | (key, value), hash|
69
- if value.is_a?(String)
70
- hash[key] = URI.decode(value)
71
- elsif value.is_a?(Symbol) || value.is_a?(Numeric)
73
+ case value
74
+ when String, Symbol, Numeric
72
75
  hash[key] = value
73
76
  end
74
77
  end
@@ -111,45 +114,27 @@ module PactBroker
111
114
  { user_options: decorator_context(options) }
112
115
  end
113
116
 
114
- def handle_exception(error)
115
- error_reference = PactBroker::Errors.generate_error_reference
116
- application_context.error_logger.call(error, error_reference, request.env)
117
- if PactBroker::Errors.reportable_error?(error)
118
- PactBroker::Errors.report(error, error_reference, request.env)
119
- end
120
- response.body = application_context.error_response_body_generator.call(error, error_reference, request.env)
121
- end
122
-
123
117
  # rubocop: disable Metrics/CyclomaticComplexity
124
118
  def params(options = {})
125
119
  return options[:default] if options.key?(:default) && request_body.empty?
126
120
 
127
121
  symbolize_names = !options.key?(:symbolize_names) || options[:symbolize_names]
128
- if symbolize_names
129
- @params_with_symbol_keys ||= JSON.parse(request_body, { symbolize_names: true }.merge(PACT_PARSING_OPTIONS)) #Not load! Otherwise it will try to load Ruby classes.
130
- else
131
- @params_with_string_keys ||= JSON.parse(request_body, { symbolize_names: false }.merge(PACT_PARSING_OPTIONS)) #Not load! Otherwise it will try to load Ruby classes.
122
+ parsed_params = if symbolize_names
123
+ @params_with_symbol_keys ||= JSON.parse(request_body, { symbolize_names: true }.merge(PACT_PARSING_OPTIONS)) #Not load! Otherwise it will try to load Ruby classes.
124
+ else
125
+ @params_with_string_keys ||= JSON.parse(request_body, { symbolize_names: false }.merge(PACT_PARSING_OPTIONS)) #Not load! Otherwise it will try to load Ruby classes.
126
+ end
127
+
128
+ if !parsed_params.is_a?(Hash) && !parsed_params.is_a?(Array)
129
+ raise "Expected JSON Object in request body but found #{parsed_params.class.name}"
132
130
  end
133
- rescue StandardError => e
134
- fragment = fragment_before_invalid_utf_8_char
135
131
 
136
- if fragment
137
- raise NonUTF8CharacterFound.new(message("errors.non_utf_8_char_in_request_body", char_number: fragment.length + 1, fragment: fragment))
138
- else
139
- raise InvalidJsonError.new(e.message)
140
- end
132
+ parsed_params
133
+ rescue StandardError => e
134
+ raise InvalidJsonError.new(e.message)
141
135
  end
142
136
  # rubocop: enable Metrics/CyclomaticComplexity
143
137
 
144
- def fragment_before_invalid_utf_8_char
145
- request_body.each_char.with_index do | char, index |
146
- if !char.valid_encoding?
147
- return index < 100 ? request_body[0...index] : request_body[index-100...index]
148
- end
149
- end
150
- nil
151
- end
152
-
153
138
  def params_with_string_keys
154
139
  params(symbolize_names: false)
155
140
  end
@@ -158,16 +143,6 @@ module PactBroker
158
143
  @pact_params ||= PactBroker::Pacts::PactParams.from_request(request, identifier_from_path)
159
144
  end
160
145
 
161
- def set_json_error_message message
162
- response.headers["Content-Type"] = "application/hal+json;charset=utf-8"
163
- response.body = { error: message }.to_json
164
- end
165
-
166
- def set_json_validation_error_messages errors
167
- response.headers["Content-Type"] = "application/hal+json;charset=utf-8"
168
- response.body = { errors: errors }.to_json
169
- end
170
-
171
146
  def request_body
172
147
  @request_body ||= request.body.to_s
173
148
  end
@@ -210,41 +185,29 @@ module PactBroker
210
185
 
211
186
  def invalid_json?
212
187
  begin
213
- params
214
- false
215
- rescue NonUTF8CharacterFound => e
216
- logger.info(e.message) # Don't use the default SemanticLogger error logging method because it will try and print out the cause which will contain non UTF-8 chars in the message
217
- set_json_error_message(e.message)
218
- response.headers["Content-Type"] = "application/hal+json;charset=utf-8"
219
- true
188
+ char_number, fragment = fragment_before_invalid_utf_8_char(request_body)
189
+ if char_number
190
+ error_message = message("errors.non_utf_8_char_in_request_body", char_number: char_number, fragment: fragment)
191
+ logger.info(error_message)
192
+ set_json_error_message(error_message)
193
+ true
194
+ else
195
+ params
196
+ false
197
+ end
220
198
  rescue StandardError => e
221
199
  message = "#{e.cause ? e.cause.class.name : e.class.name} - #{e.message}"
222
200
  logger.info(message)
223
201
  set_json_error_message(message)
224
- response.headers["Content-Type"] = "application/hal+json;charset=utf-8"
225
202
  true
226
203
  end
227
204
  end
228
205
 
229
- def validation_errors? model
230
- if (errors = model.validate).any?
231
- set_json_validation_error_messages errors
232
- true
233
- else
234
- false
235
- end
236
- end
237
-
238
- def contract_validation_errors? contract, params
239
- if (invalid = !contract.validate(params))
240
- set_json_validation_error_messages contract.errors.messages
241
- end
242
- invalid
243
- end
244
-
245
206
  def find_pacticipant name, role
246
207
  pacticipant_service.find_pacticipant_by_name(name).tap do | pacticipant |
247
- set_json_error_message("No #{role} with name '#{name}' found") if pacticipant.nil?
208
+ if pacticipant.nil?
209
+ set_json_error_message("No #{role} with name '#{name}' found", title: "Not found", type: "not_found", status: 404)
210
+ end
248
211
  end
249
212
  end
250
213
 
@@ -26,7 +26,7 @@ module PactBroker
26
26
  end
27
27
 
28
28
  def to_json
29
- decorator_class(:branch_version_decorator).new(branch_version).to_json(decorator_options)
29
+ decorator_class(:branch_version_decorator).new(branch_version).to_json(**decorator_options)
30
30
  end
31
31
 
32
32
  def delete_resource
@@ -36,7 +36,7 @@ module PactBroker
36
36
 
37
37
  def from_json
38
38
  already_existed = !!branch_version
39
- @branch_version = branch_service.find_or_create_branch_version(identifier_from_path)
39
+ @branch_version = branch_service.find_or_create_branch_version(**identifier_from_path)
40
40
  # Make it return a 201 by setting the Location header
41
41
  response.headers["Location"] = branch_version_url(branch_version, base_url) unless already_existed
42
42
  response.body = to_json
@@ -49,7 +49,7 @@ module PactBroker
49
49
  private
50
50
 
51
51
  def branch_version
52
- @branch_version ||= branch_service.find_branch_version(identifier_from_path)
52
+ @branch_version ||= branch_service.find_branch_version(**identifier_from_path)
53
53
  end
54
54
  end
55
55
  end
@@ -1,5 +1,5 @@
1
1
  require "pact_broker/api/resources/matrix"
2
- require "pact_broker/matrix/can_i_deploy_query_schema"
2
+ require "pact_broker/api/contracts/can_i_deploy_query_schema"
3
3
  require "pact_broker/matrix/parse_can_i_deploy_query"
4
4
  require "pact_broker/messages"
5
5
 
@@ -9,16 +9,9 @@ module PactBroker
9
9
  class CanIDeploy < Matrix
10
10
  include PactBroker::Messages
11
11
 
12
+ # Can't call super because it will execute the Matrix validation, not the BaseResource validation
12
13
  def malformed_request?
13
- if (errors = query_schema.call(query_params)).any?
14
- set_json_validation_error_messages(errors)
15
- true
16
- elsif !pacticipant
17
- set_json_validation_error_messages(pacticipant: [message("errors.validation.pacticipant_not_found", name: pacticipant_name)])
18
- true
19
- else
20
- false
21
- end
14
+ request.get? && validation_errors_for_schema?(schema, request.query)
22
15
  end
23
16
 
24
17
  def policy_name
@@ -27,18 +20,10 @@ module PactBroker
27
20
 
28
21
  private
29
22
 
30
- def query_schema
23
+ def schema
31
24
  PactBroker::Api::Contracts::CanIDeployQuerySchema
32
25
  end
33
26
 
34
- def pacticipant
35
- @pacticipant ||= pacticipant_service.find_pacticipant_by_name(pacticipant_name)
36
- end
37
-
38
- def pacticipant_name
39
- selectors.first.pacticipant_name
40
- end
41
-
42
27
  def parsed_query
43
28
  @parsed_query ||= PactBroker::Matrix::ParseCanIDeployQuery.call(query_params)
44
29
  end
@@ -1,8 +1,5 @@
1
1
  require "pact_broker/api/resources/matrix"
2
- require "pact_broker/matrix/can_i_deploy_query_schema"
3
- require "pact_broker/matrix/parse_can_i_deploy_query"
4
2
  require "pact_broker/api/decorators/matrix_decorator"
5
- require "pact_broker/api/decorators/matrix_text_decorator"
6
3
 
7
4
  module PactBroker
8
5
  module Api
@@ -47,7 +44,7 @@ module PactBroker
47
44
  end
48
45
 
49
46
  def to_json
50
- decorator_class(:matrix_decorator).new(results).to_json(decorator_options)
47
+ decorator_class(:matrix_decorator).new(results).to_json(**decorator_options)
51
48
  end
52
49
 
53
50
  def results
@@ -1,6 +1,4 @@
1
1
  require "pact_broker/api/resources/matrix"
2
- require "pact_broker/matrix/can_i_deploy_query_schema"
3
- require "pact_broker/matrix/parse_can_i_deploy_query"
4
2
 
5
3
  module PactBroker
6
4
  module Api
@@ -1,5 +1,4 @@
1
- require "pact_broker/matrix/can_i_deploy_query_schema"
2
- require "pact_broker/matrix/parse_can_i_deploy_query"
1
+ require "pact_broker/api/resources/can_i_deploy_pacticipant_version_by_tag_to_tag"
3
2
  require "pact_broker/api/resources/badge_methods"
4
3
 
5
4
  module PactBroker
@@ -21,7 +21,7 @@ module PactBroker
21
21
  end
22
22
 
23
23
  def to_json
24
- decorator_class(decorator_name).new(deployed_versions).to_json(decorator_options(title: title))
24
+ decorator_class(decorator_name).new(deployed_versions).to_json(**decorator_options(title: title))
25
25
  end
26
26
 
27
27
  def policy_name
@@ -43,7 +43,7 @@ module PactBroker
43
43
  end
44
44
 
45
45
  def deployed_versions
46
- @deployed_versions ||= deployed_version_service.find_currently_deployed_versions_for_environment(environment, query_params)
46
+ @deployed_versions ||= deployed_version_service.find_currently_deployed_versions_for_environment(environment, **query_params)
47
47
  end
48
48
 
49
49
  def environment_uuid
@@ -21,7 +21,7 @@ module PactBroker
21
21
  end
22
22
 
23
23
  def to_json
24
- decorator_class(decorator_name).new(released_versions).to_json(decorator_options(title: title))
24
+ decorator_class(decorator_name).new(released_versions).to_json(**decorator_options(title: title))
25
25
  end
26
26
 
27
27
  def policy_name
@@ -43,7 +43,7 @@ module PactBroker
43
43
  end
44
44
 
45
45
  def released_versions
46
- @released_versions ||= released_version_service.find_currently_supported_versions_for_environment(environment, query_params)
46
+ @released_versions ||= released_version_service.find_currently_supported_versions_for_environment(environment, **query_params)
47
47
  end
48
48
 
49
49
  def environment_uuid
@@ -21,11 +21,11 @@ module PactBroker
21
21
  end
22
22
 
23
23
  def to_json
24
- decorator_class(:dashboard_decorator).new(index_items).to_json(decorator_options)
24
+ decorator_class(:dashboard_decorator).new(index_items).to_json(**decorator_options)
25
25
  end
26
26
 
27
27
  def to_text
28
- decorator_class(:dashboard_text_decorator).new(index_items).to_text(decorator_options)
28
+ decorator_class(:dashboard_text_decorator).new(index_items).to_text(**decorator_options)
29
29
  end
30
30
 
31
31
  def policy_name
@@ -35,7 +35,7 @@ module PactBroker
35
35
  private
36
36
 
37
37
  def index_items
38
- index_service.find_index_items_for_api(identifier_from_path.merge(pagination_options))
38
+ index_service.find_index_items_for_api(**identifier_from_path.merge(pagination_options))
39
39
  end
40
40
  end
41
41
  end
@@ -33,7 +33,7 @@ module PactBroker
33
33
  end
34
34
 
35
35
  def to_json
36
- decorator_class(:deployed_version_decorator).new(deployed_version).to_json(decorator_options)
36
+ decorator_class(:deployed_version_decorator).new(deployed_version).to_json(**decorator_options)
37
37
  end
38
38
 
39
39
  def from_merge_patch_json
@@ -32,11 +32,11 @@ module PactBroker
32
32
  def from_json
33
33
  @deployed_version = deployed_version_service.find_or_create(deployed_version_uuid, version, environment, application_instance)
34
34
  response.headers["Location"] = deployed_version_url(deployed_version, base_url)
35
- response.body = decorator_class(:deployed_version_decorator).new(deployed_version).to_json(decorator_options)
35
+ response.body = decorator_class(:deployed_version_decorator).new(deployed_version).to_json(**decorator_options)
36
36
  end
37
37
 
38
38
  def to_json
39
- decorator_class(:deployed_versions_decorator).new(deployed_versions).to_json(decorator_options(title: title))
39
+ decorator_class(:deployed_versions_decorator).new(deployed_versions).to_json(**decorator_options(title: title))
40
40
  end
41
41
 
42
42
  def policy_name
@@ -43,7 +43,7 @@ module PactBroker
43
43
  end
44
44
 
45
45
  def to_json
46
- decorator_class(:environment_decorator).new(environment).to_json(decorator_options)
46
+ decorator_class(:environment_decorator).new(environment).to_json(**decorator_options)
47
47
  end
48
48
 
49
49
  def parsed_environment
@@ -35,7 +35,7 @@ module PactBroker
35
35
  end
36
36
 
37
37
  def from_json
38
- response.body = decorator_class(:environment_decorator).new(create_environment).to_json(decorator_options)
38
+ response.body = decorator_class(:environment_decorator).new(create_environment).to_json(**decorator_options)
39
39
  end
40
40
 
41
41
  def policy_name
@@ -43,7 +43,7 @@ module PactBroker
43
43
  end
44
44
 
45
45
  def to_json
46
- decorator_class(:environments_decorator).new(environments).to_json(decorator_options)
46
+ decorator_class(:environments_decorator).new(environments).to_json(**decorator_options)
47
47
  end
48
48
 
49
49
  def parsed_environment
@@ -0,0 +1,57 @@
1
+ require "pact_broker/api/decorators/validation_errors_problem_json_decorator"
2
+ require "pact_broker/api/decorators/custom_error_problem_json_decorator"
3
+
4
+ module PactBroker
5
+ module Api
6
+ module Resources
7
+ module ErrorHandlingMethods
8
+
9
+ # @override
10
+ def handle_exception(error)
11
+ error_reference = PactBroker::Errors.generate_error_reference
12
+ application_context.error_logger.call(error, error_reference, request.env)
13
+ if PactBroker::Errors.reportable_error?(error)
14
+ PactBroker::Errors.report(error, error_reference, request.env)
15
+ end
16
+ headers, body = application_context.error_response_generator.call(error, error_reference, request.env)
17
+ headers.each { | key, value | response.headers[key] = value }
18
+ response.body = body
19
+ end
20
+
21
+ def set_json_error_message detail, title: "Server error", type: "server_error", status: 500
22
+ response.headers["Content-Type"] = error_response_content_type
23
+ response.body = error_response_body(detail, title, type, status)
24
+ end
25
+
26
+ def set_json_validation_error_messages errors
27
+ response.headers["Content-Type"] = error_response_content_type
28
+ if problem_json_error_content_type?
29
+ response.body = PactBroker::Api::Decorators::ValidationErrorsProblemJSONDecorator.new(errors).to_json(**decorator_options)
30
+ else
31
+ response.body = { errors: errors }.to_json
32
+ end
33
+ end
34
+
35
+ def error_response_content_type
36
+ if problem_json_error_content_type?
37
+ "application/problem+json;charset=utf-8"
38
+ else
39
+ "application/hal+json;charset=utf-8"
40
+ end
41
+ end
42
+
43
+ def error_response_body(detail, title, type, status)
44
+ if problem_json_error_content_type?
45
+ PactBroker::Api::Decorators::CustomErrorProblemJSONDecorator.new(detail: detail, title: title, type: type, status: status).to_json(**decorator_options)
46
+ else
47
+ { error: detail }.to_json
48
+ end
49
+ end
50
+
51
+ def problem_json_error_content_type?
52
+ request.headers["Accept"]&.include?("application/problem+json")
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,70 @@
1
+ require "pact_broker/configuration"
2
+ require "pact_broker/api/decorators/runtime_error_problem_json_decorator"
3
+
4
+ module PactBroker
5
+ module Api
6
+ module Resources
7
+ class ErrorResponseGenerator
8
+ include PactBroker::Logging
9
+
10
+ # @param error [StandardError]
11
+ # @param error_reference [String] an error reference to display to the user
12
+ # @param env [Hash] the rack env
13
+ # @return [Hash, String] the response headers to set, the response body to set
14
+ def self.call error, error_reference, env = {}
15
+ body = response_body_hash(error, error_reference, env, display_message(error, obfuscated_error_message(error_reference)))
16
+ return headers(env), body.to_json
17
+ end
18
+
19
+ def self.display_message(error, obfuscated_message)
20
+ if PactBroker.configuration.show_backtrace_in_error_response?
21
+ error.message || obfuscated_message
22
+ else
23
+ PactBroker::Errors.reportable_error?(error) ? obfuscated_message : error.message
24
+ end
25
+ end
26
+
27
+ private_class_method def self.response_body_hash(error, error_reference, env, message)
28
+ if problem_json?(env)
29
+ problem_json_response_body(message, env)
30
+ else
31
+ hal_json_response_body(error, error_reference, message)
32
+ end
33
+ end
34
+
35
+ private_class_method def self.hal_json_response_body(error, error_reference, message)
36
+ response_body = {
37
+ error: {
38
+ message: message,
39
+ reference: error_reference
40
+ }
41
+ }
42
+ if PactBroker.configuration.show_backtrace_in_error_response?
43
+ response_body[:error][:backtrace] = error.backtrace
44
+ end
45
+ response_body
46
+ end
47
+
48
+ private_class_method def self.problem_json_response_body(message, env)
49
+ PactBroker::Api::Decorators::RuntimeErrorProblemJSONDecorator.new(message).to_hash(user_options: { base_url: env["pactbroker.base_url" ] })
50
+ end
51
+
52
+ private_class_method def self.obfuscated_error_message(error_reference)
53
+ "An error has occurred. The details have been logged with the reference #{error_reference}"
54
+ end
55
+
56
+ private_class_method def self.headers(env)
57
+ if problem_json?(env)
58
+ { "Content-Type" => "application/problem+json;charset=utf-8" }
59
+ else
60
+ { "Content-Type" => "application/hal+json;charset=utf-8" }
61
+ end
62
+ end
63
+
64
+ private_class_method def self.problem_json?(env)
65
+ env["HTTP_ACCEPT"]&.include?("application/problem+json")
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -22,7 +22,7 @@ module PactBroker
22
22
  end
23
23
 
24
24
  def to_json
25
- decorator_class(:integrations_decorator).new(integrations).to_json(decorator_options)
25
+ decorator_class(:integrations_decorator).new(integrations).to_json(**decorator_options)
26
26
  end
27
27
 
28
28
  def integrations
@@ -39,7 +39,7 @@ module PactBroker
39
39
  end
40
40
 
41
41
  def to_json
42
- decorator_class(:label_decorator).new(label).to_json(decorator_options)
42
+ decorator_class(:label_decorator).new(label).to_json(**decorator_options)
43
43
  end
44
44
 
45
45
  def label
@@ -30,11 +30,11 @@ module PactBroker
30
30
 
31
31
  def to_json
32
32
  response.headers["X-Pact-Consumer-Version"] = pact.consumer_version_number
33
- decorator_class(:pact_decorator).new(pact).to_json(decorator_options(metadata: metadata))
33
+ decorator_class(:pact_decorator).new(pact).to_json(**decorator_options(metadata: metadata))
34
34
  end
35
35
 
36
36
  def to_extended_json
37
- decorator_class(:extended_pact_decorator).new(pact).to_json(decorator_options(metadata: metadata))
37
+ decorator_class(:extended_pact_decorator).new(pact).to_json(**decorator_options(metadata: metadata))
38
38
  end
39
39
 
40
40
  def to_html
@@ -14,7 +14,7 @@ module PactBroker
14
14
  end
15
15
 
16
16
  def to_json
17
- decorator_class(:pact_collection_decorator).new(pacts).to_json(decorator_options)
17
+ decorator_class(:pact_collection_decorator).new(pacts).to_json(**decorator_options)
18
18
  end
19
19
 
20
20
  def pacts
@@ -23,11 +23,11 @@ module PactBroker
23
23
 
24
24
  def to_json
25
25
  summary = verification_service.verification_summary_for_consumer_version(identifier_from_path)
26
- decorator_for(summary).to_json(decorator_options(identifier_from_path))
26
+ decorator_for(summary).to_json(**decorator_options(identifier_from_path))
27
27
  end
28
28
 
29
29
  def policy_name
30
- :'verifications::verifications'
30
+ :'pacticipants::pacticipant'
31
31
  end
32
32
 
33
33
  private
@@ -29,11 +29,11 @@ module PactBroker
29
29
  end
30
30
 
31
31
  def to_json
32
- decorator_class(:matrix_decorator).new(results).to_json(decorator_options)
32
+ decorator_class(:matrix_decorator).new(results).to_json(**decorator_options)
33
33
  end
34
34
 
35
35
  def to_text
36
- decorator_class(:matrix_text_decorator).new(results).to_text(decorator_options)
36
+ decorator_class(:matrix_text_decorator).new(results).to_text(**decorator_options)
37
37
  end
38
38
 
39
39
  def policy_name
@@ -34,7 +34,7 @@ module PactBroker
34
34
  end
35
35
 
36
36
  def to_json
37
- decorator_class(:matrix_decorator).new(results).to_json(decorator_options)
37
+ decorator_class(:matrix_decorator).new(results).to_json(**decorator_options)
38
38
  end
39
39
 
40
40
  def policy_name
@@ -54,9 +54,8 @@ module PactBroker
54
54
  potential_duplicate_pacticipants?(pact_params.pacticipant_names) || merge_conflict || disallowed_modification?
55
55
  end
56
56
 
57
-
58
57
  def malformed_request?
59
- super || ((request.patch? || request.really_put?) && contract_validation_errors?(Contracts::PutPactParamsContract.new(pact_params), pact_params))
58
+ super || ((request.patch? || request.really_put?) && validation_errors_for_schema?(schema, pact_params.to_hash_for_validation))
60
59
  end
61
60
 
62
61
  def resource_exists?
@@ -78,11 +77,11 @@ module PactBroker
78
77
  end
79
78
 
80
79
  def to_json
81
- decorator_class(:pact_decorator).new(pact).to_json(decorator_options(metadata: identifier_from_path[:metadata]))
80
+ decorator_class(:pact_decorator).new(pact).to_json(**decorator_options(metadata: identifier_from_path[:metadata]))
82
81
  end
83
82
 
84
83
  def to_extended_json
85
- decorator_class(:extended_pact_decorator).new(pact).to_json(decorator_options(metadata: identifier_from_path[:metadata]))
84
+ decorator_class(:extended_pact_decorator).new(pact).to_json(**decorator_options(metadata: identifier_from_path[:metadata]))
86
85
  end
87
86
 
88
87
  def to_html
@@ -118,6 +117,10 @@ module PactBroker
118
117
  false
119
118
  end
120
119
  end
120
+
121
+ def schema
122
+ api_contract_class(:put_pact_params_contract)
123
+ end
121
124
  end
122
125
  end
123
126
  end
@@ -18,7 +18,7 @@ module PactBroker
18
18
  end
19
19
 
20
20
  def to_json
21
- decorator_class(:triggered_webhooks_decorator).new(triggered_webhooks).to_json(decorator_options(resource_title: resource_title))
21
+ decorator_class(:triggered_webhooks_decorator).new(triggered_webhooks).to_json(**decorator_options(resource_title: resource_title))
22
22
  end
23
23
 
24
24
  def policy_name
@@ -11,7 +11,7 @@ module PactBroker
11
11
  ["GET", "OPTIONS"]
12
12
  end
13
13
 
14
- def decorator_options(options)
14
+ def decorator_options(options = {})
15
15
  super(options.merge(consumer_versions: consumer_versions_from_metadata&.reverse))
16
16
  end
17
17
  end