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
@@ -0,0 +1,125 @@
1
+ require "pact_broker/api/contracts/base_contract"
2
+ require "pact_broker/webhooks/render"
3
+ require "pact_broker/webhooks/check_host_whitelist"
4
+ require "pact_broker/api/contracts/validation_helpers"
5
+
6
+ module PactBroker
7
+ module Api
8
+ module Contracts
9
+ class WebhookRequestContract < BaseContract
10
+ include ValidationHelpers
11
+
12
+ json do
13
+ required(:method).filled(:string)
14
+ required(:url).filled(:string)
15
+ end
16
+
17
+ rule(:url) do
18
+ if !valid_webhook_url?(value)
19
+ key.failure(validation_message("invalid_url"))
20
+ end
21
+ end
22
+
23
+ rule(:method) do
24
+ if !valid_http_method?(value)
25
+ key.failure(validation_message("invalid_http_method"))
26
+ end
27
+ end
28
+
29
+ rule(:method) do
30
+ if_still_valid(self) do
31
+ if !allowed_webhook_method?(value)
32
+ key.failure(http_method_error_message)
33
+ end
34
+ end
35
+ end
36
+
37
+ rule(:url) do
38
+ if_still_valid(self) do
39
+ if templated_host?(value)
40
+ key.failure(validation_message("webhook_templated_host_not_allowed"))
41
+ end
42
+ end
43
+ end
44
+
45
+ rule(:url) do
46
+ if_still_valid(self) do
47
+ if !allowed_webhook_scheme?(value)
48
+ key.failure(scheme_error_message)
49
+ end
50
+ end
51
+ end
52
+
53
+ rule(:url) do
54
+ if_still_valid(self) do
55
+ if !allowed_webhook_host?(value)
56
+ key.failure(host_error_message)
57
+ end
58
+ end
59
+ end
60
+
61
+ def allowed_webhook_method?(http_method)
62
+ PactBroker.configuration.webhook_http_method_whitelist.any? do | allowed_method |
63
+ http_method.downcase == allowed_method.downcase
64
+ end
65
+ end
66
+
67
+ def http_method_error_message
68
+ if PactBroker.configuration.webhook_http_method_whitelist.size == 1
69
+ "must be #{PactBroker.configuration.webhook_http_method_whitelist.first}. See /doc/webhooks#whitelist for more information."
70
+ else
71
+ "must be one of #{PactBroker.configuration.webhook_http_method_whitelist.join(", ")}. See /doc/webhooks#whitelist for more information."
72
+ end
73
+ end
74
+
75
+ def allowed_webhook_scheme?(url)
76
+ scheme = parse_uri(url).scheme
77
+ PactBroker.configuration.webhook_scheme_whitelist.any? do | allowed_scheme |
78
+ scheme.downcase == allowed_scheme.downcase
79
+ end
80
+ end
81
+
82
+ def scheme_error_message
83
+ "scheme must be #{PactBroker.configuration.webhook_scheme_whitelist.join(", ")}. See /doc/webhooks#whitelist for more information."
84
+ end
85
+
86
+ def parse_uri(uri_string, placeholder = "placeholder")
87
+ URI(PactBroker::Webhooks::Render.render_with_placeholder(uri_string, placeholder))
88
+ end
89
+
90
+ def allowed_webhook_host?(url)
91
+ if host_whitelist.any?
92
+ PactBroker::Webhooks::CheckHostWhitelist.call(parse_uri(url).host, host_whitelist).any?
93
+ else
94
+ true
95
+ end
96
+ end
97
+
98
+ def host_whitelist
99
+ PactBroker.configuration.webhook_host_whitelist
100
+ end
101
+
102
+ def host_error_message
103
+ "host must be in the whitelist #{PactBroker.configuration.webhook_host_whitelist.collect(&:inspect).join(", ")}. See /doc/webhooks#whitelist for more information."
104
+ end
105
+
106
+ def valid_webhook_url?(url)
107
+ uri = parse_uri(url)
108
+ uri.scheme && uri.host
109
+ rescue URI::InvalidURIError, ArgumentError
110
+ nil
111
+ end
112
+
113
+ def templated_host?(url)
114
+ parse_uri(url).host != parse_uri(url, "differentplaceholder").host
115
+ end
116
+
117
+ def if_still_valid(context)
118
+ if !context.rule_error?(context.path.keys)
119
+ yield
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,3 @@
1
+ Dir.glob(File.expand_path(File.join(__FILE__, "..", "contracts", "*.rb"))).sort.each do | path |
2
+ require path
3
+ end
@@ -0,0 +1,36 @@
1
+ # Formats a message string into application/problem+json format.
2
+
3
+ module PactBroker
4
+ module Api
5
+ module Decorators
6
+ class CustomErrorProblemJSONDecorator
7
+
8
+ # @option title [String]
9
+ # @option type [String]
10
+ # @option detail [String]
11
+ # @option status [Integer] HTTP status code
12
+ def initialize(title:, type:, detail:, status: )
13
+ @title = title
14
+ @type = type
15
+ @detail = detail
16
+ @status = status
17
+ end
18
+
19
+ # @return [Hash]
20
+ def to_hash(user_options: {}, **__other)
21
+ {
22
+ "title" => @title,
23
+ "type" => "#{user_options[:base_url]}/problem/#{@type}",
24
+ "detail" => @detail,
25
+ "status" => @status
26
+ }
27
+ end
28
+
29
+ # @return [String] JSON
30
+ def to_json(*args, **kwargs)
31
+ to_hash(*args, **kwargs).to_json
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -17,8 +17,8 @@ module PactBroker
17
17
  to_hash(options).to_json
18
18
  end
19
19
 
20
- def to_text(options)
21
- data = items(index_items, options[:user_options][:base_url])
20
+ def to_text(user_options:, **_other)
21
+ data = items(index_items, user_options[:base_url])
22
22
  printer = TablePrint::Printer.new(data)
23
23
  printer.table_print + "\n"
24
24
  end
@@ -32,7 +32,7 @@ module PactBroker
32
32
 
33
33
  # TODO rather than remove the contract keys that we added in the super class,
34
34
  # it would be better to inherit from a shared super class
35
- def to_hash(options = {})
35
+ def to_hash(*)
36
36
  keys_to_remove = represented.content_hash.keys
37
37
  super.each_with_object({}) do | (key, value), new_hash |
38
38
  new_hash[key] = value unless keys_to_remove.include?(key)
@@ -16,18 +16,18 @@ module PactBroker
16
16
  @query_results_with_deployment_status_summary = query_results_with_deployment_status_summary
17
17
  end
18
18
 
19
- def to_json(options)
20
- to_hash(options).to_json
19
+ def to_json(*args, **kwargs)
20
+ to_hash(*args, **kwargs).to_json
21
21
  end
22
22
 
23
- def to_hash(options)
23
+ def to_hash(user_options:, **_other)
24
24
  {
25
25
  summary: {
26
26
  deployable: deployable,
27
27
  reason: reason
28
28
  },
29
29
  notices: notices,
30
- matrix: matrix(options[:user_options][:base_url])
30
+ matrix: matrix(user_options[:base_url])
31
31
  }.tap do | hash |
32
32
  hash[:summary].merge!(query_results_with_deployment_status_summary.deployment_status_summary.counts)
33
33
  end
@@ -14,7 +14,7 @@ module PactBroker
14
14
  @lines = lines
15
15
  end
16
16
 
17
- def to_text(_options)
17
+ def to_text(**_options)
18
18
  json_decorator = PactBroker::Api::Decorators::MatrixDecorator.new(lines)
19
19
  data = lines.collect do | line |
20
20
  Line.new(line.consumer_name, line.consumer_version_number, line.pact_revision_number, line.provider_name, line.provider_version_number, line.verification_number, line.success)
@@ -9,7 +9,7 @@ module PactBroker
9
9
 
10
10
  include Timestamps
11
11
 
12
- def to_hash(options = {})
12
+ def to_hash(*)
13
13
  parsed_content = represented.content_hash
14
14
  if parsed_content.is_a?(::Hash)
15
15
  parsed_content.merge super
@@ -1,6 +1,7 @@
1
1
  require "roar/json/hal"
2
2
  require "pact_broker/api/pact_broker_urls"
3
3
  require_relative "embedded_version_decorator"
4
+ require_relative "pagination_links"
4
5
  require "pact_broker/domain/pacticipant"
5
6
  require "pact_broker/api/decorators/pacticipant_decorator"
6
7
 
@@ -11,6 +12,8 @@ module PactBroker
11
12
 
12
13
  collection :entries, :as => :pacticipants, :class => PactBroker::Domain::Pacticipant, :extend => PactBroker::Api::Decorators::PacticipantDecorator, embedded: true
13
14
 
15
+ include PaginationLinks
16
+
14
17
  link :self do | options |
15
18
  pacticipants_url options[:base_url]
16
19
  end
@@ -34,7 +37,7 @@ module PactBroker
34
37
  end
35
38
 
36
39
  class DeprecatedPacticipantDecorator < PactBroker::Api::Decorators::PacticipantDecorator
37
- property :title, getter: ->(_something) { "DEPRECATED - Please use the embedded pacticipants collection" }
40
+ property :title, getter: ->(_) { "DEPRECATED - Please use the embedded pacticipants collection" }
38
41
  end
39
42
 
40
43
  class NonEmbeddedPacticipantCollectionDecorator < BaseDecorator
@@ -43,7 +46,7 @@ module PactBroker
43
46
 
44
47
  # TODO deprecate this - breaking change for v 3.0
45
48
  class DeprecatedPacticipantCollectionDecorator < PacticipantCollectionDecorator
46
- def to_hash(options = {})
49
+ def to_hash(options)
47
50
  embedded_pacticipant_hash = super
48
51
  non_embedded_pacticipant_hash = NonEmbeddedPacticipantCollectionDecorator.new(represented).to_hash(options)
49
52
  embedded_pacticipant_hash.merge(non_embedded_pacticipant_hash)
@@ -106,7 +106,8 @@ module PactBroker
106
106
  }]
107
107
  end
108
108
 
109
- def to_hash options
109
+ # representable passes through the kwargs from to_json as normal args
110
+ def to_hash(options)
110
111
  h = super
111
112
  dasherized = DasherizedVersionDecorator.new(represented).to_hash(options)
112
113
  if dasherized["_embedded"]
@@ -15,7 +15,10 @@ module PactBroker
15
15
  property :provider_version_branch
16
16
 
17
17
  collection :consumer_version_selectors, default: PactBroker::Pacts::Selectors.new, class: PactBroker::Pacts::Selector do
18
- property :main_branch
18
+ property :main_branch, setter: -> (fragment:, represented:, **) {
19
+ represented.main_branch = fragment
20
+ represented.latest = true
21
+ }
19
22
  property :tag
20
23
  property :branch, setter: -> (fragment:, represented:, **) {
21
24
  represented.branch = fragment
@@ -8,6 +8,17 @@ module PactBroker
8
8
  include Roar::JSON::HAL
9
9
  include Roar::JSON::HAL::Links
10
10
 
11
+ property :page, getter: lambda { |represented:, **|
12
+ if represented.respond_to?(:current_page)
13
+ {
14
+ number: represented.current_page,
15
+ size: represented.page_size,
16
+ totalElements: represented.pagination_record_count,
17
+ totalPages: represented.page_count,
18
+ }
19
+ end
20
+ }
21
+
11
22
  link :next do | context |
12
23
  if represented.respond_to?(:current_page) &&
13
24
  represented.respond_to?(:page_count) &&
@@ -0,0 +1,34 @@
1
+ # Formats a message string into application/problem+json format.
2
+
3
+ module PactBroker
4
+ module Api
5
+ module Decorators
6
+ class RuntimeErrorProblemJSONDecorator
7
+
8
+ # @param message [String]
9
+ def initialize(message)
10
+ @message = message
11
+ end
12
+
13
+ # @return [Hash]
14
+ def to_hash(user_options:, **)
15
+ {
16
+ "title" => "Server error",
17
+ "type" => "#{user_options[:base_url]}/problems/server_error",
18
+ "detail" => message,
19
+ "status" => 500
20
+ }
21
+ end
22
+
23
+ # @return [String] JSON
24
+ def to_json(*args, **kwargs)
25
+ to_hash(*args, **kwargs).to_json
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :message
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,66 @@
1
+ # Formats a nested Hash of errors as it comes out of the Dry Validation library
2
+ # into application/problem+json format.
3
+ require "pact_broker/string_refinements"
4
+
5
+ module PactBroker
6
+ module Api
7
+ module Decorators
8
+ class ValidationErrorsProblemJSONDecorator
9
+ using PactBroker::StringRefinements
10
+
11
+
12
+ # @param errors [Hash]
13
+ def initialize(errors)
14
+ @errors = errors
15
+ end
16
+
17
+ # @return [Hash]
18
+ def to_hash(user_options:, **)
19
+ error_list = []
20
+ walk_errors(errors, error_list, "", user_options[:base_url])
21
+ {
22
+ "title" => "Validation errors",
23
+ "type" => "#{user_options[:base_url]}/problems/validation-error",
24
+ "status" => 400,
25
+ "instance" => "/",
26
+ "errors" => error_list
27
+ }
28
+ end
29
+
30
+ # @return [String] JSON
31
+ def to_json(*args, **kwargs)
32
+ to_hash(*args, **kwargs).to_json
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :errors
38
+
39
+ # The path is meant to be implemented using JSON Pointer, but this will probably do for now.
40
+ # As per https://gregsdennis.github.io/Manatee.Json/usage/pointer.html
41
+ # the only things that need to be escaped are "~" and "/", which are unlikely to be used
42
+ # in a key name. You get what you deserve if you've done that.
43
+ def walk_errors(object, list, path, base_url)
44
+ if object.is_a?(Hash)
45
+ object.each { | key, value | walk_errors(value, list, "#{path}/#{key}", base_url) }
46
+ elsif object.is_a?(Array)
47
+ object.each { | value | walk_errors(value, list, path, base_url) }
48
+ elsif object.is_a?(String)
49
+ append_error(list, object, path, base_url)
50
+ end
51
+ end
52
+
53
+ def append_error(list, message, path, base_url)
54
+ error = {
55
+ "type" => "#{base_url}/problems/invalid-body-property-value",
56
+ "title" => "Validation error",
57
+ "detail" => message,
58
+ "status" => 400
59
+ }
60
+ error["pointer"] = path.tr(".", "/") if path.present?
61
+ list << error
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -9,17 +9,17 @@ module PactBroker
9
9
  class VerifiablePactDecorator < BaseDecorator
10
10
  include PactBroker::Pacts::Metadata
11
11
 
12
- property :shortDescription, getter: -> (context) { PactBroker::Pacts::VerifiablePactMessages.new(context[:represented], nil).pact_version_short_description }
12
+ property :shortDescription, getter: lambda { | represented:, ** | PactBroker::Pacts::VerifiablePactMessages.new(represented, nil).pact_version_short_description }
13
13
 
14
14
  nested :verificationProperties do
15
15
  include PactBroker::Api::PactBrokerUrls
16
16
 
17
17
  property :pending,
18
- if: ->(context) { context[:options][:user_options][:include_pending_status] }
18
+ if: ->(options:, **_other) { options.dig(:user_options, :include_pending_status) }
19
19
  property :wip,
20
- if: -> (context) { context[:represented].wip }
20
+ if: -> (represented:, **_other) { represented.wip }
21
21
  property :notices,
22
- getter: -> (context) { context[:decorator].notices(context[:options][:user_options]) }
22
+ getter: -> (decorator:, options:, **) { decorator.notices(options[:user_options]) }
23
23
 
24
24
  def notices(user_options)
25
25
  metadata = represented.wip ? { wip: true } : nil
@@ -18,7 +18,7 @@ module PactBroker
18
18
 
19
19
  property :uuid
20
20
 
21
- property :description, getter: lambda { |context| context[:represented].display_description }
21
+ property :description, getter: lambda { |represented:, **| represented.display_description }
22
22
 
23
23
  property :consumer, class: Domain::WebhookPacticipant, default: nil do
24
24
  property :name
@@ -42,7 +42,6 @@ module PactBroker
42
42
  title: represented.display_description,
43
43
  href: webhook_url(represented.uuid, options[:base_url])
44
44
  }
45
-
46
45
  end
47
46
 
48
47
  link :'pb:execute' do | options |
@@ -108,7 +107,7 @@ module PactBroker
108
107
  }
109
108
  end
110
109
 
111
- def from_json represented
110
+ def from_json(represented)
112
111
  super.tap do | webhook |
113
112
  if webhook.events == nil
114
113
  webhook.events = [PactBroker::Webhooks::WebhookEvent.new(name: PactBroker::Webhooks::WebhookEvent::DEFAULT_EVENT_NAME)]
@@ -56,10 +56,12 @@ module PactBroker
56
56
  end
57
57
  end
58
58
 
59
- property :error, :extend => ErrorDecorator, if: lambda { |context| context[:options][:user_options][:show_response] }
59
+ property :error, :extend => ErrorDecorator, if: lambda { |options:, **| options.dig(:user_options, :show_response) }
60
60
  property :request, :extend => HTTPRequestDecorator
61
- property :response, :extend => HTTPResponseDecorator, if: lambda { |context| context[:options][:user_options][:show_response] }
62
- property :response_hidden_message, as: :message, exec_context: :decorator, if: lambda { |context| !context[:options][:user_options][:show_response] }
61
+ property :response, :extend => HTTPResponseDecorator, if: lambda { |options:, **| options.dig(:user_options, :show_response) }
62
+ property :message,
63
+ if: lambda { |options:, **| !options.dig(:user_options, :show_response) },
64
+ getter: lambda { |options:, **| PactBroker::Messages.message("messages.response_body_hidden", base_url: options.dig(:user_options, :base_url)) }
63
65
  property :logs
64
66
  property :success?, as: :success
65
67
 
@@ -77,15 +79,6 @@ module PactBroker
77
79
  href: options.fetch(:resource_url)
78
80
  }
79
81
  end
80
-
81
- def to_hash(options)
82
- @to_hash_options = options
83
- super
84
- end
85
-
86
- def response_hidden_message
87
- PactBroker::Messages.message("messages.response_body_hidden", base_url: @to_hash_options[:user_options][:base_url])
88
- end
89
82
  end
90
83
  end
91
84
  end
@@ -30,16 +30,16 @@ module PactBroker
30
30
  end
31
31
 
32
32
  def malformed_request?
33
- super || (request.post? && validation_errors?(webhook))
33
+ super || (request.post? && validation_errors_for_schema?)
34
34
  end
35
35
 
36
36
  def to_json
37
- decorator_class(:webhooks_decorator).new(webhooks).to_json(decorator_options(resource_title: "Webhooks"))
37
+ decorator_class(:webhooks_decorator).new(webhooks).to_json(**decorator_options(resource_title: "Webhooks"))
38
38
  end
39
39
 
40
40
  def from_json
41
41
  saved_webhook = webhook_service.create(next_uuid, webhook, consumer, provider)
42
- response.body = decorator_class(:webhook_decorator).new(saved_webhook).to_json(decorator_options)
42
+ response.body = decorator_class(:webhook_decorator).new(saved_webhook).to_json(**decorator_options)
43
43
  end
44
44
 
45
45
  def policy_name
@@ -56,14 +56,8 @@ module PactBroker
56
56
 
57
57
  private
58
58
 
59
- def validation_errors? webhook
60
- errors = webhook_service.errors(webhook)
61
-
62
- unless errors.empty?
63
- set_json_validation_error_messages(errors.messages)
64
- end
65
-
66
- !errors.empty?
59
+ def schema
60
+ api_contract_class(:webhook_contract)
67
61
  end
68
62
 
69
63
  def consumer
@@ -37,7 +37,7 @@ module PactBroker
37
37
  badge_url
38
38
  rescue StandardError => e
39
39
  # Want to render a badge, even if there's an error
40
- badge_service.error_badge_url("error", ErrorResponseBodyGenerator.display_message(e, "reference: #{PactBroker::Errors.generate_error_reference}"))
40
+ badge_service.error_badge_url("error", ErrorResponseGenerator.display_message(e, "reference: #{PactBroker::Errors.generate_error_reference}"))
41
41
  end
42
42
  end
43
43