pact_broker 2.99.0 → 2.102.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -0
  3. data/Gemfile +1 -0
  4. data/README.md +14 -4
  5. data/db/migrations/20220622_default_allow_dangerous_contract_modification_to_false_for_new_installations.rb +22 -0
  6. data/db/migrations/20220625_delete_pacticipants_with_no_name.rb +62 -0
  7. data/db/migrations/migration_helper.rb +6 -0
  8. data/docs/CONFIGURATION.md +3 -1
  9. data/docs/api/PACTICIPANTS.md +290 -0
  10. data/docs/api/WEBHOOKS.md +40 -40
  11. data/lib/pact_broker/api/contracts/pacticipant_create_schema.rb +28 -0
  12. data/lib/pact_broker/api/decorators/embedded_version_decorator.rb +0 -1
  13. data/lib/pact_broker/api/decorators/reason_decorator.rb +1 -15
  14. data/lib/pact_broker/api/decorators/triggered_webhook_decorator.rb +1 -2
  15. data/lib/pact_broker/api/resources/all_webhooks.rb +1 -4
  16. data/lib/pact_broker/api/resources/base_resource.rb +58 -5
  17. data/lib/pact_broker/api/resources/branch_version.rb +10 -1
  18. data/lib/pact_broker/api/resources/clean.rb +11 -9
  19. data/lib/pact_broker/api/resources/currently_deployed_versions_for_environment.rb +0 -4
  20. data/lib/pact_broker/api/resources/currently_supported_versions_for_environment.rb +0 -4
  21. data/lib/pact_broker/api/resources/deployed_version.rb +20 -16
  22. data/lib/pact_broker/api/resources/deployed_versions_for_version_and_environment.rb +1 -1
  23. data/lib/pact_broker/api/resources/environment.rb +5 -5
  24. data/lib/pact_broker/api/resources/environments.rb +1 -5
  25. data/lib/pact_broker/api/resources/label.rb +4 -0
  26. data/lib/pact_broker/api/resources/matrix_for_consumer_and_provider.rb +10 -0
  27. data/lib/pact_broker/api/resources/pact.rb +14 -5
  28. data/lib/pact_broker/api/resources/pact_webhooks.rb +1 -4
  29. data/lib/pact_broker/api/resources/pacticipant.rb +11 -5
  30. data/lib/pact_broker/api/resources/pacticipant_resource_methods.rb +0 -1
  31. data/lib/pact_broker/api/resources/pacticipant_webhooks.rb +1 -4
  32. data/lib/pact_broker/api/resources/pacticipants.rb +7 -6
  33. data/lib/pact_broker/api/resources/provider_pacts_for_verification.rb +19 -11
  34. data/lib/pact_broker/api/resources/publish_contracts.rb +12 -16
  35. data/lib/pact_broker/api/resources/released_version.rb +20 -8
  36. data/lib/pact_broker/api/resources/released_versions_for_version_and_environment.rb +11 -7
  37. data/lib/pact_broker/api/resources/tag.rb +7 -3
  38. data/lib/pact_broker/api/resources/verifications.rb +7 -9
  39. data/lib/pact_broker/api/resources/version.rb +8 -8
  40. data/lib/pact_broker/api/resources/webhook.rb +5 -4
  41. data/lib/pact_broker/api/resources/webhook_execution.rb +4 -6
  42. data/lib/pact_broker/config/runtime_configuration.rb +1 -1
  43. data/lib/pact_broker/contracts/contract_to_publish.rb +4 -0
  44. data/lib/pact_broker/contracts/contracts_to_publish.rb +4 -0
  45. data/lib/pact_broker/contracts/service.rb +23 -5
  46. data/lib/pact_broker/doc/views/index/pacticipant-branch-version.markdown +13 -2
  47. data/lib/pact_broker/doc/views/provider-pacts-for-verification.markdown +1 -1
  48. data/lib/pact_broker/domain/pacticipant.rb +1 -0
  49. data/lib/pact_broker/domain/tag.rb +8 -32
  50. data/lib/pact_broker/domain/verification.rb +3 -2
  51. data/lib/pact_broker/domain/version.rb +26 -10
  52. data/lib/pact_broker/locale/en.yml +8 -4
  53. data/lib/pact_broker/matrix/deployment_status_summary.rb +28 -19
  54. data/lib/pact_broker/matrix/parse_query.rb +5 -0
  55. data/lib/pact_broker/matrix/quick_row.rb +5 -2
  56. data/lib/pact_broker/matrix/repository.rb +3 -3
  57. data/lib/pact_broker/matrix/resolved_selector.rb +47 -10
  58. data/lib/pact_broker/matrix/service.rb +17 -7
  59. data/lib/pact_broker/matrix/unresolved_selector.rb +14 -2
  60. data/lib/pact_broker/messages.rb +0 -15
  61. data/lib/pact_broker/pacticipants/find_potential_duplicate_pacticipant_names.rb +3 -3
  62. data/lib/pact_broker/pacticipants/repository.rb +5 -4
  63. data/lib/pact_broker/pacticipants/service.rb +11 -1
  64. data/lib/pact_broker/pacts/generate_sha.rb +1 -0
  65. data/lib/pact_broker/pacts/pact_version.rb +1 -0
  66. data/lib/pact_broker/pacts/verifiable_pact_messages.rb +4 -2
  67. data/lib/pact_broker/repositories/helpers.rb +13 -0
  68. data/lib/pact_broker/string_refinements.rb +8 -0
  69. data/lib/pact_broker/test/http_test_data_builder.rb +15 -0
  70. data/lib/pact_broker/test/test_data_builder.rb +20 -0
  71. data/lib/pact_broker/ui/controllers/index.rb +3 -1
  72. data/lib/pact_broker/ui/views/index/show.haml +3 -4
  73. data/lib/pact_broker/ui/views/matrix/show.haml +5 -2
  74. data/lib/pact_broker/verifications/pact_version_provider_tag_successful_verification.rb +15 -0
  75. data/lib/pact_broker/version.rb +1 -1
  76. data/lib/pact_broker/versions/branch_service.rb +7 -0
  77. data/lib/pact_broker/versions/branch_version_repository.rb +17 -0
  78. data/lib/pact_broker/webhooks/pact_and_verification_parameters.rb +1 -1
  79. data/lib/rack/pact_broker/cascade.rb +87 -0
  80. data/lib/webmachine/describe_routes.rb +43 -9
  81. metadata +8 -5
  82. data/lib/db.rb +0 -79
  83. data/lib/pact_broker/api/resources/default_base_resource.rb +0 -0
@@ -10,13 +10,14 @@ module PactBroker
10
10
  extend PactBroker::Repositories
11
11
  extend PactBroker::Services
12
12
  include PactBroker::Logging
13
+ extend PactBroker::Messages
13
14
 
14
15
  def self.messages_for_potential_duplicate_pacticipants(pacticipant_names, base_url)
15
16
  messages = []
16
17
  pacticipant_names.each do | name |
17
18
  potential_duplicate_pacticipants = find_potential_duplicate_pacticipants(name)
18
19
  if potential_duplicate_pacticipants.any?
19
- messages << Messages.potential_duplicate_pacticipant_message(name, potential_duplicate_pacticipants, base_url)
20
+ messages << potential_duplicate_pacticipant_message(name, potential_duplicate_pacticipants, base_url)
20
21
  end
21
22
  end
22
23
  messages
@@ -98,6 +99,15 @@ module PactBroker
98
99
  pacticipant
99
100
  end
100
101
  end
102
+
103
+ private_class_method def self.potential_duplicate_pacticipant_message(new_name, potential_duplicate_pacticipants, base_url)
104
+ existing_names = potential_duplicate_pacticipants.
105
+ collect{ | p | "* #{p.name}" }.join("\n")
106
+ message("errors.duplicate_pacticipant",
107
+ new_name: new_name,
108
+ existing_names: existing_names,
109
+ base_url: base_url)
110
+ end
101
111
  end
102
112
  end
103
113
  end
@@ -7,6 +7,7 @@ require "pact_broker/pacts/content"
7
7
  module PactBroker
8
8
  module Pacts
9
9
  class GenerateSha
10
+ # @param [String] json_content
10
11
  def self.call json_content, _options = {}
11
12
  content_for_sha = if PactBroker.configuration.base_equality_only_on_content_that_affects_verification_results
12
13
  extract_verifiable_content_for_sha(json_content)
@@ -179,4 +179,5 @@ end
179
179
  # latest_pact_publication_ids_for_consumer_versions | latest_pact_publication_ids_for_consumer_v_pact_version_id_fkey | (pact_version_id) REFERENCES pact_versions(id) ON DELETE CASCADE
180
180
  # latest_verification_id_for_pact_version_and_provider_version | latest_v_id_for_pv_and_pv_pact_version_id_fk | (pact_version_id) REFERENCES pact_versions(id) ON DELETE CASCADE
181
181
  # pact_publications | pact_publications_pact_version_id_fkey | (pact_version_id) REFERENCES pact_versions(id)
182
+ # pact_version_provider_tag_successful_verifications | pact_version_provider_tag_successful_verifications_pv_id_fk | (pact_version_id) REFERENCES pact_versions(id) ON DELETE CASCADE
182
183
  # verifications | verifications_pact_version_id_fkey | (pact_version_id) REFERENCES pact_versions(id)
@@ -31,7 +31,7 @@ module PactBroker
31
31
  version_text = head_consumer_tags.size == 1 || branches.size == 1 ? "version" : "versions"
32
32
  if wip?
33
33
  # WIP pacts will always have tags, because it is part of the definition of being a WIP pact
34
- "The pact at #{pact_version_url} is being verified because it is a 'work in progress' pact (ie. it is the pact for the latest #{version_text} of #{consumer_name} #{joined_head_consumer_tags_and_branches} and is still in pending state). #{READ_MORE_WIP}"
34
+ "The pact at #{pact_version_url} is being verified because it is a 'work in progress' pact (ie. it is the pact for the latest #{version_text} of #{consumer_name} #{joined_head_consumer_tags_and_branches} and it has not yet been successfully verified by #{pending_provider_branch_or_tags_description("a")} when the pact's application version was explicitly specified in the consumer version selectors). #{READ_MORE_WIP}"
35
35
  else
36
36
  criteria_or_criterion = selectors.size > 1 ? "criteria" : "criterion"
37
37
  version_or_versions = pluralize("the consumer version", selectors.size)
@@ -40,7 +40,9 @@ module PactBroker
40
40
  end
41
41
 
42
42
  def pending_reason
43
- if pending?
43
+ if pending? && wip?
44
+ "This pact is in pending state for this version of #{provider_name} because it was included as a 'work in progress' pact. If this verification fails, it will not cause the overall build to fail. #{READ_MORE_PENDING}"
45
+ elsif pending?
44
46
  "This pact is in pending state for this version of #{provider_name} because a successful verification result for #{pending_provider_branch_or_tags_description("a")} has not yet been published. If this verification fails, it will not cause the overall build to fail. #{READ_MORE_PENDING}"
45
47
  else
46
48
  "This pact has previously been successfully verified by #{non_pending_provider_branch_or_tags_description}. If this verification fails, it will fail the build. #{READ_MORE_PENDING}"
@@ -55,6 +55,19 @@ module PactBroker
55
55
  select_append(Sequel[model.table_name].*)
56
56
  end
57
57
 
58
+ # @param [Symbol] max_column the name of the column of which to calculate the maxiumum
59
+ # @param [Array<Symbol>] group_by_columns the names of the columns by which to group
60
+ def max_group_by(max_column, group_by_columns, &extra_criteria_block)
61
+ maximums_base_query = extra_criteria_block ? extra_criteria_block.call(self) : self
62
+ maximums = maximums_base_query.select_group(*group_by_columns).select_append(Sequel.function(:max, max_column).as(:max_value))
63
+
64
+ max_join = group_by_columns.each_with_object({ Sequel[:maximums][:max_value] => max_column }) do | column_name, joins |
65
+ joins[Sequel[:maximums][column_name]] = column_name
66
+ end
67
+
68
+ join(maximums, max_join, table_alias: :maximums)
69
+ end
70
+
58
71
  def select_for_subquery column
59
72
  if mysql? #stoopid mysql doesn't allow you to modify datasets with subqueries
60
73
  column_name = column.respond_to?(:alias) ? column.alias : column
@@ -4,6 +4,10 @@ module PactBroker
4
4
  def blank?
5
5
  true
6
6
  end
7
+
8
+ def present?
9
+ false
10
+ end
7
11
  end
8
12
 
9
13
  refine Numeric do
@@ -13,6 +17,10 @@ module PactBroker
13
17
  end
14
18
 
15
19
  refine String do
20
+ def present?
21
+ !blank?
22
+ end
23
+
16
24
  def not_blank?
17
25
  !blank?
18
26
  end
@@ -286,6 +286,7 @@ module PactBroker
286
286
  "githubVerificationStatus" => "${pactbroker.githubVerificationStatus}",
287
287
  "providerVersionNumber" => "${pactbroker.providerVersionNumber}",
288
288
  "providerVersionTags" => "${pactbroker.providerVersionTags}",
289
+ "providerVersionBranch" => "${pactbroker.providerVersionBranch}",
289
290
  "canIMerge" => "${pactbroker.providerMainBranchGithubVerificationStatus}"
290
291
  }
291
292
  }
@@ -323,6 +324,20 @@ module PactBroker
323
324
  self
324
325
  end
325
326
 
327
+ def can_i_merge(pacticipant:, version:)
328
+ can_i_merge_response = client.get("matrix", { q: [pacticipant: pacticipant, version: version], latestby: "cvp", mainBranch: true, latest: true }.compact ).tap { |response| check_for_error(response) }
329
+ can = !!(can_i_merge_response.body["summary"] || {})["deployable"]
330
+ puts "can-i-merge #{pacticipant} version #{version}: #{can ? 'yes' : 'no'}"
331
+ summary = can_i_merge_response.body["summary"]
332
+ verification_result_urls = (can_i_merge_response.body["matrix"] || []).collect do | row |
333
+ row.dig("verificationResult", "_links", "self", "href")
334
+ end.compact
335
+ summary.merge!("verification_result_urls" => verification_result_urls)
336
+ puts summary.to_yaml
337
+ separate
338
+ self
339
+ end
340
+
326
341
  def delete_integration(consumer:, provider:)
327
342
  puts "Deleting all data for the integration between #{consumer} and #{provider}"
328
343
  client.delete("integrations/provider/#{encode(provider)}/consumer/#{encode(consumer)}").tap { |response| check_for_error(response) }
@@ -572,6 +572,26 @@ module PactBroker
572
572
  }.to_json
573
573
  end
574
574
 
575
+ def fixed_json_content(consumer_name, provider_name, differentiator)
576
+ {
577
+ "consumer" => {
578
+ "name" => consumer_name
579
+ },
580
+ "provider" => {
581
+ "name" => provider_name
582
+ },
583
+ "interactions" => [{
584
+ "request" => {
585
+ "method" => "GET",
586
+ "path" => "/things/#{differentiator}"
587
+ },
588
+ "response" => {
589
+ "status" => 200
590
+ }
591
+ }],
592
+ }.to_json
593
+ end
594
+
575
595
  private
576
596
 
577
597
  def create_pacticipant_version(version_number, pacticipant, params = {})
@@ -1,5 +1,6 @@
1
1
  require "pact_broker/ui/controllers/base_controller"
2
2
  require "pact_broker/ui/view_models/index_items"
3
+ require "pact_broker/string_refinements"
3
4
  require "haml"
4
5
 
5
6
  module PactBroker
@@ -7,6 +8,7 @@ module PactBroker
7
8
  module Controllers
8
9
  class Index < Base
9
10
  include PactBroker::Services
11
+ using PactBroker::StringRefinements
10
12
 
11
13
  get "/" do
12
14
  set_headers
@@ -27,7 +29,7 @@ module PactBroker
27
29
 
28
30
  index_items = index_service.find_index_items(options)
29
31
 
30
- if index_items.blank? && !search.blank?
32
+ if index_items.empty? && !search.blank?
31
33
  error_messages << "No pacticipants found matching: \"#{search}\""
32
34
  end
33
35
 
@@ -7,10 +7,9 @@
7
7
  %h1.page-header
8
8
  Pacts
9
9
 
10
- - unless errors.blank?
11
- - errors.each do | error |
12
- %div.alert.alert-danger
13
- = error
10
+ - errors.each do | error |
11
+ %div.alert.alert-danger
12
+ = error
14
13
 
15
14
  %form{action: "#{base_url}"}
16
15
  .search-field
@@ -70,12 +70,14 @@
70
70
  %input{name: 'q[]latest', value: 'true', hidden: true, class: 'latest-flag'}
71
71
 
72
72
 
73
- - if options.latest || options.tag
73
+ %input{name: 'latest', value: options.latest.to_s, hidden: true }
74
+ %input{name: 'mainBranch', value: options.mainBranch.to_s, hidden: true}
75
+
76
+ - if options.tag
74
77
  .selector
75
78
  %label{for: 'to'}
76
79
  = options.latest ? 'To (tag)' : 'With all (tagged)'
77
80
  %input{name: 'tag', id: 'to', value: options.tag }
78
- %input{name: 'latest', value: options.latest.to_s, hidden: true}
79
81
 
80
82
  - if options.environment_name
81
83
  .selector
@@ -83,6 +85,7 @@
83
85
  To environment
84
86
  %input{name: 'environment', id: 'environment', value: options.environment_name }
85
87
 
88
+
86
89
  %div.top-of-group.form-check
87
90
  %input{type: 'radio', name: "latestby", class: 'form-check-input', value: '', id: 'all_rows', checked: options.all_rows_checked}
88
91
  %label{for: 'all_rows', class: "form-check-label"}
@@ -9,3 +9,18 @@ module PactBroker
9
9
  end
10
10
  end
11
11
  end
12
+
13
+ # Table: pact_version_provider_tag_successful_verifications
14
+ # Columns:
15
+ # id | integer | PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
16
+ # pact_version_id | integer | NOT NULL
17
+ # provider_version_tag_name | text | NOT NULL
18
+ # wip | boolean | NOT NULL
19
+ # verification_id | integer |
20
+ # execution_date | timestamp without time zone | NOT NULL
21
+ # Indexes:
22
+ # pact_version_provider_tag_successful_verifications_pkey | PRIMARY KEY btree (id)
23
+ # pact_version_provider_tag_verifications_pv_pvtn_wip_unique | UNIQUE btree (pact_version_id, provider_version_tag_name, wip)
24
+ # Foreign key constraints:
25
+ # pact_version_provider_tag_successful_verifications_pv_id_fk | (pact_version_id) REFERENCES pact_versions(id) ON DELETE CASCADE
26
+ # pact_version_provider_tag_successful_verifications_v_id_fk | (verification_id) REFERENCES verifications(id) ON DELETE SET NULL
@@ -1,3 +1,3 @@
1
1
  module PactBroker
2
- VERSION = "2.99.0"
2
+ VERSION = "2.102.0"
3
3
  end
@@ -1,12 +1,19 @@
1
1
  require "pact_broker/logging"
2
2
  require "pact_broker/repositories"
3
3
  require "pact_broker/messages"
4
+ require "forwardable"
4
5
 
5
6
  module PactBroker
6
7
  module Versions
7
8
  class BranchService
8
9
  extend PactBroker::Repositories
9
10
 
11
+ class << self
12
+ extend Forwardable
13
+ delegate [:delete_branch_version] => :branch_version_repository
14
+ end
15
+
16
+
10
17
  def self.find_branch_version(pacticipant_name:, branch_name:, version_number:, **)
11
18
  BranchVersion.where(
12
19
  version: PactBroker::Domain::Version.where_pacticipant_name_and_version_number(pacticipant_name, version_number),
@@ -16,6 +16,23 @@ module PactBroker
16
16
  branch_version
17
17
  end
18
18
 
19
+ # Deletes a branch version - that is, removes a version from a branch.
20
+ # Updates the branch head if the deleted branch version was the latest for the branch.
21
+ #
22
+ # @param [PactBroker::Versions::BranchVersion] the branch version to delete
23
+ def delete_branch_version(branch_version)
24
+ latest = branch_version.latest?
25
+ branch = branch_version.latest? ? branch_version.branch : nil
26
+ deleted = branch_version.delete
27
+ if latest
28
+ new_head_branch_version = BranchVersion.find_latest_for_branch(branch)
29
+ if new_head_branch_version
30
+ PactBroker::Versions::BranchHead.new(branch: branch, branch_version: new_head_branch_version).upsert
31
+ end
32
+ end
33
+ deleted
34
+ end
35
+
19
36
  private
20
37
 
21
38
  def find_or_create_branch(pacticipant, branch_name)
@@ -173,7 +173,7 @@ module PactBroker
173
173
  if webhook_context.key?(:provider_version_branch)
174
174
  webhook_context[:provider_version_branch] || ""
175
175
  else
176
- verification&.provider_version&.branch || ""
176
+ verification&.provider_version&.branch_names&.last || ""
177
177
  end
178
178
  end
179
179
 
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is a modified version of the Rack::Cascade class from https://github.com/rack/rack/blob/2833813/lib/rack/cascade.rb
4
+ # that short circuts the cascade if a response body is provided for a 404/403 response.
5
+ # This is to allow the UI and API to be in a cascade, but allows the UI
6
+ # to return a 404 page when the route matches, but there is no domain object found.
7
+ # If we don't do this, then the 404 from the UI causes an API response to be returned.
8
+
9
+
10
+ # This does not work. Do not use it. Have not yet worked out why.
11
+
12
+ module Rack
13
+ # Rack::Cascade tries a request on several apps, and returns the
14
+ # first response that is not 404 or 405 (or in a list of configured
15
+ # status codes). If all applications tried return one of the configured
16
+ # status codes, return the last response.
17
+
18
+ module PactBroker
19
+ class Cascade
20
+ # deprecated, no longer used
21
+ NotFound = [404, { CONTENT_TYPE => "text/plain" }, []]
22
+
23
+ # An array of applications to try in order.
24
+ attr_reader :apps
25
+
26
+ # Set the apps to send requests to, and what statuses result in
27
+ # cascading. Arguments:
28
+ #
29
+ # apps: An enumerable of rack applications.
30
+ # cascade_for: The statuses to use cascading for. If a response is received
31
+ # from an app, the next app is tried.
32
+ def initialize(apps, cascade_for = [404, 405])
33
+ @apps = []
34
+ apps.each { |app| add app }
35
+
36
+ @cascade_for = {}
37
+ [*cascade_for].each { |status| @cascade_for[status] = true }
38
+ end
39
+
40
+ # Call each app in order. If the responses uses a status that requires
41
+ # cascading, try the next app. If all responses require cascading,
42
+ # return the response from the last app.
43
+ def call(env)
44
+ return [404, { CONTENT_TYPE => "text/plain" }, []] if @apps.empty?
45
+ result = nil
46
+ last_body = nil
47
+
48
+ @apps.each_with_index do |app, i|
49
+ # The SPEC says that the body must be closed after it has been iterated
50
+ # by the server, or if it is replaced by a middleware action. Cascade
51
+ # replaces the body each time a cascade happens. It is assumed that nil
52
+ # does not respond to close, otherwise the previous application body
53
+ # will be closed. The final application body will not be closed, as it
54
+ # will be passed to the server as a result.
55
+ last_body.close if last_body.respond_to? :close
56
+ result = app.call(env)
57
+
58
+ puts result.last
59
+
60
+ # If it is a 404/403 AND the response body is empty, then try the next app
61
+ if @cascade_for.include?(result[0].to_i) && result[2].respond_to?(:empty?) && result[2].empty?
62
+ last_body = result[2]
63
+ else
64
+ puts "returned from #{i} of #{@apps.size}"
65
+ # otherwise, return the result
66
+ return result
67
+ end
68
+ end
69
+
70
+ result
71
+ end
72
+
73
+ # Append an app to the list of apps to cascade. This app will
74
+ # be tried last.
75
+ def add(app)
76
+ @apps << app
77
+ end
78
+
79
+ # Whether the given app is one of the apps to cascade to.
80
+ def include?(app)
81
+ @apps.include?(app)
82
+ end
83
+
84
+ alias_method :<<, :add
85
+ end
86
+ end
87
+ end
@@ -5,6 +5,7 @@ module Webmachine
5
5
 
6
6
  Route = Struct.new(
7
7
  :path,
8
+ :path_spec,
8
9
  :resource_class,
9
10
  :resource_name,
10
11
  :resource_class_location,
@@ -23,6 +24,38 @@ module Webmachine
23
24
  def path_include?(component)
24
25
  path.include?(component)
25
26
  end
27
+
28
+ def route_param_names
29
+ path_spec.select { | component | component.is_a?(Symbol) }
30
+ end
31
+
32
+ # Creates a Webmachine Resource for the given route for use in tests.
33
+ # @param [Hash] env the rack env from which to build the request
34
+ # @param [PactBroker::ApplicationContext] application_context the application context
35
+ # @param [Hash] path_param_values concrete parameter values from which to construct the path
36
+ # @return [Webmachine::Resource] the webmachine resource for the request
37
+ def build_resource(env, application_context, path_param_values)
38
+ path = "/" + path_spec.collect{ | part | part.is_a?(Symbol) ? (path_param_values[part] || "missing-param") : part }.join("/")
39
+
40
+ path_params = route_param_names.each_with_object({}){ | name, new_params | new_params[name] = path_param_values[name] }
41
+ path_info = {
42
+ application_context: application_context,
43
+ resource_name: resource_name
44
+ }.merge(path_params)
45
+
46
+ rack_req = ::Rack::Request.new({ "REQUEST_METHOD" => "GET", "rack.input" => StringIO.new("") }.merge(env) )
47
+ dummy_request = Webmachine::Adapters::Rack::RackRequest.new(
48
+ rack_req.env["REQUEST_METHOD"],
49
+ path,
50
+ Webmachine::Headers.from_cgi({"HTTP_HOST" => "example.org"}.merge(env)),
51
+ Webmachine::Adapters::Rack::RequestBody.new(rack_req),
52
+ {},
53
+ {},
54
+ rack_req.env
55
+ )
56
+ dummy_request.path_info = path_info
57
+ resource_class.new(dummy_request, Webmachine::Response.new)
58
+ end
26
59
  end
27
60
 
28
61
  def self.call(webmachine_applications, search_term: nil)
@@ -36,24 +69,25 @@ module Webmachine
36
69
  end
37
70
 
38
71
  def self.paths_to_resource_class_mappings(webmachine_application)
39
- webmachine_application.routes.collect do | route |
40
- resource_path_absolute = Pathname.new(source_location_for(route.resource))
72
+ webmachine_application.routes.collect do | webmachine_route |
73
+ resource_path_absolute = Pathname.new(source_location_for(webmachine_route.resource))
41
74
  Route.new({
42
- path: "/" + route.path_spec.collect{ |part| part.is_a?(Symbol) ? ":#{part}" : part }.join("/"),
43
- resource_class: route.resource,
44
- resource_name: route.instance_variable_get(:@bindings)[:resource_name],
75
+ path: "/" + webmachine_route.path_spec.collect{ |part| part.is_a?(Symbol) ? ":#{part}" : part }.join("/"),
76
+ path_spec: webmachine_route.path_spec,
77
+ resource_class: webmachine_route.resource,
78
+ resource_name: webmachine_route.instance_variable_get(:@bindings)[:resource_name],
45
79
  resource_class_location: resource_path_absolute.relative_path_from(Pathname.pwd).to_s
46
- }.merge(info_from_resource_instance(route)))
47
- end
80
+ }.merge(info_from_resource_instance(webmachine_route)))
81
+ end.reject{ | route | route.resource_class == Webmachine::Trace::TraceResource }
48
82
  end
49
83
 
50
- def self.info_from_resource_instance(route)
84
+ def self.info_from_resource_instance(webmachine_route)
51
85
  with_no_logging do
52
86
  path_info = { application_context: OpenStruct.new, pacticipant_name: "foo", pacticipant_version_number: "1", resource_name: "foo" }
53
87
  path_info.default = "1"
54
88
  dummy_request = Webmachine::Adapters::Rack::RackRequest.new("GET", "/", Webmachine::Headers["host" => "example.org"], nil, {}, {}, { "REQUEST_METHOD" => "GET" })
55
89
  dummy_request.path_info = path_info
56
- dummy_resource = route.resource.new(dummy_request, Webmachine::Response.new)
90
+ dummy_resource = webmachine_route.resource.new(dummy_request, Webmachine::Response.new)
57
91
  if dummy_resource
58
92
  {
59
93
  allowed_methods: dummy_resource.allowed_methods,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pact_broker
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.99.0
4
+ version: 2.102.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bethany Skurrie
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-05-16 00:00:00.000000000 Z
13
+ date: 2022-07-07 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: httparty
@@ -584,10 +584,12 @@ files:
584
584
  - db/migrations/20211120_create_pact_version_provider_tag_successful_verifications.rb
585
585
  - db/migrations/20211121_migrate_pact_version_provider_tag_successful_verifications_data.rb
586
586
  - db/migrations/20220303_increase_consumer_version_selector_hashes_column_size.rb
587
+ - db/migrations/20220622_default_allow_dangerous_contract_modification_to_false_for_new_installations.rb
588
+ - db/migrations/20220625_delete_pacticipants_with_no_name.rb
587
589
  - db/migrations/migration_helper.rb
588
590
  - docs/CONFIGURATION.md
591
+ - docs/api/PACTICIPANTS.md
589
592
  - docs/api/WEBHOOKS.md
590
- - lib/db.rb
591
593
  - lib/pact/doc/README.md
592
594
  - lib/pact/doc/doc_file.rb
593
595
  - lib/pact/doc/generate.rb
@@ -608,6 +610,7 @@ files:
608
610
  - lib/pact_broker/api/contracts/dry_validation_predicates.rb
609
611
  - lib/pact_broker/api/contracts/dry_validation_workarounds.rb
610
612
  - lib/pact_broker/api/contracts/environment_schema.rb
613
+ - lib/pact_broker/api/contracts/pacticipant_create_schema.rb
611
614
  - lib/pact_broker/api/contracts/pacticipant_name_contract.rb
612
615
  - lib/pact_broker/api/contracts/pacticipant_name_validation.rb
613
616
  - lib/pact_broker/api/contracts/pacticipant_schema.rb
@@ -705,7 +708,6 @@ files:
705
708
  - lib/pact_broker/api/resources/currently_deployed_versions_for_environment.rb
706
709
  - lib/pact_broker/api/resources/currently_supported_versions_for_environment.rb
707
710
  - lib/pact_broker/api/resources/dashboard.rb
708
- - lib/pact_broker/api/resources/default_base_resource.rb
709
711
  - lib/pact_broker/api/resources/deployed_version.rb
710
712
  - lib/pact_broker/api/resources/deployed_versions_for_version_and_environment.rb
711
713
  - lib/pact_broker/api/resources/environment.rb
@@ -1076,6 +1078,7 @@ files:
1076
1078
  - lib/rack/hal_browser/redirect.rb
1077
1079
  - lib/rack/pact_broker/add_pact_broker_version_header.rb
1078
1080
  - lib/rack/pact_broker/add_vary_header.rb
1081
+ - lib/rack/pact_broker/cascade.rb
1079
1082
  - lib/rack/pact_broker/configurable_make_it_later.rb
1080
1083
  - lib/rack/pact_broker/convert_404_to_hal.rb
1081
1084
  - lib/rack/pact_broker/convert_file_extension_to_accept_header.rb
@@ -1222,7 +1225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1222
1225
  - !ruby/object:Gem::Version
1223
1226
  version: '0'
1224
1227
  requirements: []
1225
- rubygems_version: 3.3.13
1228
+ rubygems_version: 3.3.17
1226
1229
  signing_key:
1227
1230
  specification_version: 4
1228
1231
  summary: See description
data/lib/db.rb DELETED
@@ -1,79 +0,0 @@
1
- require "sequel"
2
- require "sequel/connection_pool/threaded"
3
- require "yaml"
4
- require "pact_broker/logging"
5
- require "erb"
6
- require "pact_broker/project_root"
7
- require "fileutils"
8
-
9
- module DB
10
- include PactBroker::Logging
11
- ##
12
- # Sequel by default does not test connections in its connection pool before
13
- # handing them to a client. To enable connection testing you need to load the
14
- # "connection_validator" extension like below. The connection validator
15
- # extension is configurable, by default it only checks connections once per
16
- # hour:
17
- #
18
- # http://sequel.rubyforge.org/rdoc-plugins/files/lib/sequel/extensions/connection_validator_rb.html
19
- #
20
- # Because most of our applications so far are accessed infrequently, there is
21
- # very little overhead in checking each connection when it is requested. This
22
- # takes care of stale connections.
23
- #
24
- # A gotcha here is that it is not enough to enable the "connection_validator"
25
- # extension, we also need to specify that we want to use the threaded connection
26
- # pool, as noted in the documentation for the extension.
27
- #
28
- def self.connect db_credentials
29
- # Keep this conifiguration in sync with lib/pact_broker/app.rb#configure_database_connection
30
- Sequel.datetime_class = DateTime
31
- if ENV["DEBUG"] == "true" && ENV["PACT_BROKER_SQL_LOG_LEVEL"] != "none"
32
- logger = Logger.new($stdout)
33
- end
34
- if db_credentials.fetch("adapter") == "sqlite"
35
- FileUtils.mkdir_p(File.dirname(db_credentials.fetch("database")))
36
- end
37
- con = Sequel.connect(db_credentials.merge(:logger => logger, :pool_class => Sequel::ThreadedConnectionPool, :encoding => "utf8"))
38
- con.extension(:connection_validator)
39
- con.extension(:pagination)
40
- con.extension(:statement_timeout)
41
- con.extension(:any_not_empty)
42
- #con.extension(:caller_logging)
43
- con.timezone = :utc
44
- con.run("SET sql_mode='STRICT_TRANS_TABLES';") if db_credentials[:adapter].to_s =~ /mysql/
45
- con
46
- end
47
-
48
- def self.connection_for_env env
49
- config = configuration_for_env(env)
50
- logger.info "Connecting to #{env} #{config['adapter']} database #{config['database']}."
51
- connect config
52
- end
53
-
54
- def self.configuration_for_env env
55
- database_yml = PactBroker.project_root.join("config","database.yml")
56
- config = YAML.load(ERB.new(File.read(database_yml)).result)
57
- config.fetch(env).fetch(ENV.fetch("DATABASE_ADAPTER","default"))
58
- end
59
-
60
- def self.sqlite?
61
- !!(PACT_BROKER_DB.adapter_scheme.to_s =~ /sqlite/)
62
- end
63
-
64
- def self.mysql?
65
- !!(PACT_BROKER_DB.adapter_scheme.to_s =~ /mysql/)
66
- end
67
-
68
- def self.postgres?
69
- !!(PACT_BROKER_DB.adapter_scheme.to_s =~ /postgres/)
70
- end
71
-
72
- PACT_BROKER_DB ||= connection_for_env ENV.fetch("RACK_ENV")
73
-
74
- def self.health_check
75
- PACT_BROKER_DB.synchronize do |c|
76
- PACT_BROKER_DB.valid_connection? c
77
- end
78
- end
79
- end