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
@@ -159,7 +159,7 @@ module PactBroker
159
159
 
160
160
  def find_latest_triggered_webhooks consumer, provider
161
161
  # policy already applied to pact
162
- deliberately_unscoped(TriggeredWebhook)
162
+ scope_for(TriggeredWebhook)
163
163
  .where(consumer: consumer, provider: provider)
164
164
  .latest_triggered_webhooks
165
165
  .all
@@ -29,6 +29,7 @@ module PactBroker
29
29
  extend PactBroker::Messages
30
30
 
31
31
  delegate [
32
+ :create,
32
33
  :find_by_uuid,
33
34
  :find_all,
34
35
  :update_triggered_webhook_status,
@@ -37,34 +38,15 @@ module PactBroker
37
38
  :find_latest_triggered_webhooks_for_pact,
38
39
  :fail_retrying_triggered_webhooks,
39
40
  :find_triggered_webhooks_for_pact,
40
- :find_triggered_webhooks_for_verification
41
+ :find_triggered_webhooks_for_verification,
42
+ :delete_by_uuid
41
43
  ] => :webhook_repository
42
44
 
43
- # Not actually a UUID. Ah well.
44
- def valid_uuid_format?(uuid)
45
- !!(uuid =~ /^[A-Za-z0-9_\-]{16,}$/)
46
- end
47
45
 
48
46
  def next_uuid
49
47
  SecureRandom.urlsafe_base64
50
48
  end
51
49
 
52
- def errors webhook, uuid = nil
53
- contract = PactBroker::Api::Contracts::WebhookContract.new(webhook)
54
- contract.validate(webhook.attributes)
55
- messages = contract.errors.messages
56
-
57
- if uuid && !valid_uuid_format?(uuid)
58
- messages["uuid"] = [message("errors.validation.invalid_webhook_uuid")]
59
- end
60
-
61
- OpenStruct.new(messages: messages, empty?: messages.empty?, any?: messages.any?)
62
- end
63
-
64
- def create uuid, webhook, consumer, provider
65
- webhook_repository.create uuid, webhook, consumer, provider
66
- end
67
-
68
50
  def update_by_uuid uuid, params
69
51
  webhook = webhook_repository.find_by_uuid(uuid)
70
52
  maintain_redacted_params(webhook, params)
@@ -72,10 +54,6 @@ module PactBroker
72
54
  webhook_repository.update_by_uuid uuid, webhook
73
55
  end
74
56
 
75
- def delete_by_uuid uuid
76
- webhook_repository.delete_by_uuid uuid
77
- end
78
-
79
57
  def delete_all_webhhook_related_objects_by_pacticipant pacticipant
80
58
  webhook_repository.delete_by_pacticipant(pacticipant)
81
59
  end
@@ -10,6 +10,7 @@ module PactBroker
10
10
  module Webhooks
11
11
  class TriggeredWebhook < Sequel::Model(:triggered_webhooks)
12
12
  using PactBroker::HashRefinements
13
+ set_primary_key :id
13
14
  plugin :timestamps, update_on_create: true
14
15
  plugin :serialization, :json, :event_context
15
16
 
@@ -4,6 +4,7 @@ require "pact_broker/repositories/helpers"
4
4
  module PactBroker
5
5
  module Webhooks
6
6
  class WebhookEvent < Sequel::Model
7
+ set_primary_key :id
7
8
  plugin :timestamps, update_on_create: true
8
9
 
9
10
  CONTRACT_PUBLISHED = "contract_published"
@@ -0,0 +1,22 @@
1
+ require "webmachine"
2
+ require "webmachine/application_monkey_patch"
3
+ require "webmachine/adapters/rack_mapped"
4
+ require "webmachine/application_monkey_patch"
5
+ require "webmachine/render_error_monkey_patch"
6
+
7
+
8
+ module Webmachine
9
+ def self.build_rack_api(application_context)
10
+ api = Webmachine::Application.new do |app|
11
+ yield app
12
+ end
13
+
14
+ api.application_context = application_context
15
+
16
+ api.configure do |config|
17
+ config.adapter = :RackMapped
18
+ end
19
+
20
+ api.adapter
21
+ end
22
+ end
@@ -45,7 +45,7 @@ module Rack
45
45
  end
46
46
 
47
47
  def validate(uri)
48
- decoded_path = URI.decode(uri.path)
48
+ decoded_path = URI.decode_www_form_component(uri.path)
49
49
  if decoded_path.include?("\n")
50
50
  message("errors.new_line_in_url_path")
51
51
  elsif decoded_path.include?("\t")
@@ -7,7 +7,7 @@ module Rack
7
7
  extend self
8
8
 
9
9
  WEB_ASSET_EXTENSIONS = %w[.js .woff .woff2 .css .png .html .map .ttf .ico].freeze
10
- API_CONTENT_TYPES = %w[application/hal+json application/json text/csv application/yaml text/plain].freeze
10
+ API_CONTENT_TYPES = %w[application/hal+json application/problem+json application/json text/csv application/yaml text/plain].freeze
11
11
 
12
12
  def request_for_ui?(env)
13
13
  !(request_for_api?(env))
@@ -15,11 +15,12 @@ module Rack
15
15
  module PactBroker
16
16
  module UseWhen
17
17
  class ConditionallyUseMiddleware
18
- def initialize(app, condition_proc, middleware, *args, &block)
18
+ def initialize(app, condition_proc, middleware, *args, **kwargs, &block)
19
19
  @app_without_middleware = app
20
20
  @condition_proc = condition_proc
21
21
  @middleware = middleware
22
22
  @args = args
23
+ @kwargs = kwargs
23
24
  @block = block
24
25
  end
25
26
 
@@ -33,12 +34,12 @@ module Rack
33
34
 
34
35
  private
35
36
 
36
- attr_reader :app_without_middleware, :condition_proc, :middleware, :args, :block
37
+ attr_reader :app_without_middleware, :condition_proc, :middleware, :args, :kwargs, :block
37
38
 
38
39
  def app_with_middleware
39
40
  @app_with_middleware ||= begin
40
41
  rack_builder = ::Rack::Builder.new
41
- rack_builder.use middleware, *args, &block
42
+ rack_builder.use middleware, *args, **kwargs, &block
42
43
  rack_builder.run app_without_middleware
43
44
  rack_builder.to_app
44
45
  end
@@ -46,8 +47,8 @@ module Rack
46
47
  end
47
48
 
48
49
  refine Rack::Builder do
49
- def use_when(condition_proc, middleware, *args, &block)
50
- use(ConditionallyUseMiddleware, condition_proc, middleware, *args, &block)
50
+ def use_when(condition_proc, middleware, *args, **kwargs, &block)
51
+ use(ConditionallyUseMiddleware, condition_proc, middleware, *args, **kwargs, &block)
51
52
  end
52
53
  end
53
54
  end
@@ -0,0 +1,13 @@
1
+ require "moments"
2
+
3
+ module Sequel
4
+ module Plugins
5
+ module Age
6
+ module InstanceMethods
7
+ def age
8
+ @age ||= Moments.difference(Time.now, created_at.to_time)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ require "webmachine/application"
2
+
3
+ class Webmachine::Application
4
+ def application_context= application_context
5
+ @application_context = application_context
6
+ # naughty, but better than setting each route manually
7
+ routes.each do | route |
8
+ route.instance_variable_get(:@bindings)[:application_context] = application_context
9
+ end
10
+ end
11
+
12
+ def application_context
13
+ @application_context
14
+ end
15
+ end
@@ -1,7 +1,9 @@
1
1
  require "webmachine/adapters/rack_mapped"
2
+ require "pact_broker/string_refinements"
2
3
 
3
4
  module Webmachine
4
5
  class DescribeRoutes
6
+ using PactBroker::StringRefinements
5
7
 
6
8
  Route = Struct.new(
7
9
  :path,
@@ -11,6 +13,7 @@ module Webmachine
11
13
  :resource_class_location,
12
14
  :allowed_methods,
13
15
  :policy_class,
16
+ :schemas,
14
17
  keyword_init: true) do
15
18
 
16
19
  def [](key)
@@ -77,33 +80,57 @@ module Webmachine
77
80
  resource_class: webmachine_route.resource,
78
81
  resource_name: webmachine_route.instance_variable_get(:@bindings)[:resource_name],
79
82
  resource_class_location: resource_path_absolute.relative_path_from(Pathname.pwd).to_s
80
- }.merge(info_from_resource_instance(webmachine_route)))
83
+ }.merge(info_from_resource_instance(webmachine_route, webmachine_application.application_context)))
81
84
  end.reject{ | route | route.resource_class == Webmachine::Trace::TraceResource }
82
85
  end
83
86
 
84
- def self.info_from_resource_instance(webmachine_route)
87
+ def self.info_from_resource_instance(webmachine_route, application_context)
85
88
  with_no_logging do
86
- path_info = { application_context: OpenStruct.new, pacticipant_name: "foo", pacticipant_version_number: "1", resource_name: "foo" }
89
+ path_info = { application_context: application_context, pacticipant_name: "foo", pacticipant_version_number: "1", resource_name: "foo" }
87
90
  path_info.default = "1"
88
- dummy_request = Webmachine::Adapters::Rack::RackRequest.new("GET", "/", Webmachine::Headers["host" => "example.org"], nil, {}, {}, { "REQUEST_METHOD" => "GET" })
89
- dummy_request.path_info = path_info
91
+ dummy_request = dummy_request(http_method: "GET", path_info: path_info)
92
+
90
93
  dummy_resource = webmachine_route.resource.new(dummy_request, Webmachine::Response.new)
91
94
  if dummy_resource
92
95
  {
93
96
  allowed_methods: dummy_resource.allowed_methods,
94
- }
97
+ schemas: dummy_resource.respond_to?(:schema, true) && dummy_resource.send(:schema) ? schemas(dummy_resource.allowed_methods, webmachine_route.resource, path_info) : nil
98
+ }.compact
95
99
  else
96
100
  {}
97
101
  end
98
102
  end
99
103
  rescue StandardError => e
100
- puts "Could not determine instance info for #{route.resource}. #{e.class} - #{e.message}"
104
+ puts "Could not determine instance info for #{webmachine_route.resource}. #{e.class} - #{e.message}"
101
105
  {}
102
106
  end
103
107
 
108
+ # This is not entirely accurate, because some GET requests have schemas too, but we can't tell that statically at the moment
109
+ def self.schemas(allowed_methods, resource, path_info)
110
+ (allowed_methods - ["GET", "OPTIONS", "DELETE"]).collect do | http_method |
111
+ resource.new(dummy_request(http_method: http_method, path_info: path_info), Webmachine::Response.new).send(:schema)
112
+ end.uniq.collect do | schema_class |
113
+ {
114
+ class: schema_class,
115
+ location: source_location_for(schema_class)
116
+ }
117
+ end
118
+ end
119
+
120
+ def self.dummy_request(http_method: "GET", path_info: )
121
+ dummy_request = Webmachine::Adapters::Rack::RackRequest.new(http_method, "/", Webmachine::Headers["host" => "example.org"], nil, {}, {}, { "REQUEST_METHOD" => http_method })
122
+ dummy_request.path_info = path_info
123
+ dummy_request
124
+ end
125
+
104
126
  def self.source_location_for(clazz)
105
127
  first_instance_method_name = (clazz.instance_methods(false) + clazz.private_instance_methods(false)).first
106
- clazz.instance_method(first_instance_method_name).source_location.first
128
+ if first_instance_method_name
129
+ clazz.instance_method(first_instance_method_name).source_location.first
130
+ else
131
+ # have a guess!
132
+ "lib/" + clazz.name.snakecase.gsub("::", "/") + ".rb"
133
+ end
107
134
  end
108
135
 
109
136
  # If we don't turn off the logging, we get metrics logging due to the instantiation of the Webmachine::RackRequest class
@@ -0,0 +1,70 @@
1
+ require "webmachine/errors"
2
+ require "pact_broker/string_refinements"
3
+
4
+ # Monkey patches the render_error method so that it returns hal+json or problem+json instead of text/html
5
+
6
+ module Webmachine
7
+ using PactBroker::StringRefinements
8
+
9
+ class << self
10
+ alias_method :original_render_error, :render_error
11
+ end
12
+
13
+ # Renders a standard error message body for the response. The
14
+ # standard messages are defined in localization files.
15
+ # @param [Integer] code the response status code
16
+ # @param [Request] req the request object
17
+ # @param [Response] req the response object
18
+ # @param [Hash] options keys to override the defaults when rendering
19
+ # the response body
20
+ def self.render_error(code, req, res, options={})
21
+ if text_html_error_content_type?(req)
22
+ Webmachine.original_render_error(code, req, res, options)
23
+ else
24
+ render_error_for_api(code, req, res, options)
25
+ end
26
+ end
27
+
28
+ def self.render_error_for_api(code, req, res, options)
29
+ res.code = code
30
+ unless res.body
31
+ title, message = t(["errors.#{code}.title", "errors.#{code}.message"],
32
+ **{ :method => req.method,
33
+ :error => res.error}.merge(options))
34
+
35
+ title = options[:title] if options[:title]
36
+ message = options[:message] if options[:message]
37
+
38
+ res.body = error_response_body(message, title, title.dasherize.gsub(/^\d+\-/, ""), code, req)
39
+ res.headers[CONTENT_TYPE] = error_response_content_type(req)
40
+ end
41
+ ensure_content_length(res)
42
+ ensure_date_header(res)
43
+ end
44
+
45
+ def self.text_html_error_content_type?(request)
46
+ request.headers["Accept"]&.include?("text/html")
47
+ end
48
+
49
+ def self.problem_json_error_content_type?(request)
50
+ request.headers["Accept"]&.include?("application/problem+json")
51
+ end
52
+
53
+ def self.error_response_content_type(request)
54
+ if problem_json_error_content_type?(request)
55
+ "application/problem+json;charset=utf-8"
56
+ elsif text_html_error_content_type?(request)
57
+ "text/html;charset=utf-8"
58
+ else
59
+ "application/json;charset=utf-8"
60
+ end
61
+ end
62
+
63
+ def self.error_response_body(detail, title, type, status, request)
64
+ if problem_json_error_content_type?(request)
65
+ PactBroker::Api::Decorators::CustomErrorProblemJSONDecorator.new(detail: detail, title: title, type: type, status: status).to_json
66
+ else
67
+ { error: detail }.to_json
68
+ end
69
+ end
70
+ end
data/pact_broker.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |gem|
20
20
  if Dir.exist?(".git")
21
21
  Dir.chdir(File.expand_path(__dir__)) do
22
22
  include_patterns = %w[lib/**/* db/**/* docs/**/*.md public/**/* vendor/**/* LICENSE.txt README.md CHANGELOG.md Gemfile pact_broker.gemspec]
23
- exclude_patterns = %w[db/test/**/*]
23
+ exclude_patterns = %w[db/test/**/* lib/**/*/README.md]
24
24
  include_list = include_patterns.flat_map{ | pattern | Dir.glob(pattern) } - exclude_patterns.flat_map{ | pattern | Dir.glob(pattern) }
25
25
 
26
26
  `git ls-files -z`.split("\x0") & include_list
@@ -49,23 +49,13 @@ Gem::Specification.new do |gem|
49
49
  gem.require_paths = ["lib"]
50
50
  gem.license = "MIT"
51
51
 
52
- #gem.add_runtime_dependency 'pact'
53
52
  gem.add_runtime_dependency "json", "~> 2.3"
53
+ gem.add_runtime_dependency "psych", "~> 4.0" # TODO identify breaking changes and see if we can use 5
54
54
  gem.add_runtime_dependency "roar", "~> 1.1"
55
- gem.add_runtime_dependency "reform", "~> 2.3.3"
56
- gem.add_runtime_dependency "dry-validation", "~> 0.10.5"
57
- # if dry-container is not locked, get this error:
58
- # An error occurred while loading spec_helper.
59
- # Failure/Error: require "reform/form/dry"
60
- # NoMethodError:
61
- # undefined method `call' for nil:NilClass
62
- # # /Users/beth.skurrie/.gem/ruby/2.7.5/gems/dry-container-0.10.0/lib/dry/container/mixin.rb:151:in `register'
63
- gem.add_runtime_dependency "dry-container", "0.8.0"
64
- # /usr/local/bundle/gems/dry-validation-0.10.7/lib/dry/validation/schema/class_interface.rb:7:in `<module:Validation>' [dry-configurable] default value as positional argument to settings is deprecated and will be removed in the next major version
65
- # Provide a `default:` keyword argument instead
66
- gem.add_runtime_dependency "dry-configurable", "0.12.1"
55
+ gem.add_runtime_dependency "dry-validation", "~> 1.8"
56
+ gem.add_runtime_dependency "reform", "~> 2.6"
67
57
  gem.add_runtime_dependency "sequel", "~> 5.28"
68
- gem.add_runtime_dependency "webmachine", "1.6.0"
58
+ gem.add_runtime_dependency "webmachine", ">= 2.0.0.beta", "< 3.0"
69
59
  gem.add_runtime_dependency "semver2", "~> 3.4.2"
70
60
  gem.add_runtime_dependency "rack", ">= 2.2.3", "~> 2.2"
71
61
  gem.add_runtime_dependency "redcarpet", ">= 3.5.1", "~>3.5"
@@ -75,12 +65,11 @@ Gem::Specification.new do |gem|
75
65
  gem.add_runtime_dependency "haml", "~>5.0"
76
66
  gem.add_runtime_dependency "sucker_punch", "~>2.0"
77
67
  gem.add_runtime_dependency "rack-protection", ">= 2.0.8.1", "< 3.0"
78
- gem.add_runtime_dependency "dry-types", "~> 0.10.3" # https://travis-ci.org/pact-foundation/pact_broker/jobs/249448621
79
- gem.add_runtime_dependency "dry-logic", "0.4.2" # Later version cases ArgumentError: wrong number of arguments
80
68
  gem.add_runtime_dependency "table_print", "~> 1.5"
81
69
  gem.add_runtime_dependency "semantic_logger", "~> 4.11"
82
- gem.add_runtime_dependency "sanitize", "6.0"
70
+ gem.add_runtime_dependency "sanitize", "~> 6.0"
83
71
  gem.add_runtime_dependency "wisper", "~> 2.0"
84
72
  gem.add_runtime_dependency "anyway_config", "~> 2.1"
85
73
  gem.add_runtime_dependency "request_store", "~> 1.5"
74
+ gem.add_runtime_dependency "moments", "~> 0.2"
86
75
  end