pact_broker 2.106.0 → 2.107.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/Gemfile +3 -0
  4. data/db/migrations/20230131_add_cons_ver_id_ndx_to_latest_pp_id_for_cons_ver.rb +8 -4
  5. data/db/migrations/20230216_add_branch_heads_branch_version_id_index.rb +21 -0
  6. data/db/migrations/20230428_add_index_for_webhook_executions_pact_publication_id.rb +17 -0
  7. data/lib/pact_broker/api/contracts/base_contract.rb +22 -7
  8. data/lib/pact_broker/api/contracts/can_i_deploy_query_schema.rb +34 -0
  9. data/lib/pact_broker/api/contracts/configuration.rb +2 -0
  10. data/lib/pact_broker/api/contracts/consumer_version_selector_contract.rb +140 -0
  11. data/lib/pact_broker/api/contracts/dry_validation_errors_formatter.rb +50 -0
  12. data/lib/pact_broker/api/contracts/dry_validation_macros.rb +79 -0
  13. data/lib/pact_broker/api/contracts/dry_validation_methods.rb +71 -0
  14. data/lib/pact_broker/api/contracts/environment_schema.rb +19 -33
  15. data/lib/pact_broker/api/contracts/pacticipant_create_schema.rb +4 -17
  16. data/lib/pact_broker/api/contracts/pacticipant_schema.rb +15 -24
  17. data/lib/pact_broker/api/contracts/pacts_for_verification_json_query_schema.rb +37 -146
  18. data/lib/pact_broker/api/contracts/pacts_for_verification_query_string_schema.rb +7 -20
  19. data/lib/pact_broker/api/contracts/publish_contracts_contract_contract.rb +62 -0
  20. data/lib/pact_broker/api/contracts/publish_contracts_schema.rb +25 -124
  21. data/lib/pact_broker/api/contracts/put_pact_params_contract.rb +21 -26
  22. data/lib/pact_broker/api/contracts/utf_8_validation.rb +2 -0
  23. data/lib/pact_broker/api/contracts/validation_helpers.rb +71 -0
  24. data/lib/pact_broker/api/contracts/verification_contract.rb +10 -29
  25. data/lib/pact_broker/api/contracts/webhook_contract.rb +20 -172
  26. data/lib/pact_broker/api/contracts/webhook_pacticipant_contract.rb +33 -0
  27. data/lib/pact_broker/api/contracts/webhook_request_contract.rb +125 -0
  28. data/lib/pact_broker/api/contracts.rb +3 -0
  29. data/lib/pact_broker/api/decorators/custom_error_problem_json_decorator.rb +4 -4
  30. data/lib/pact_broker/api/decorators/dashboard_text_decorator.rb +2 -2
  31. data/lib/pact_broker/api/decorators/extended_pact_decorator.rb +1 -1
  32. data/lib/pact_broker/api/decorators/matrix_decorator.rb +4 -4
  33. data/lib/pact_broker/api/decorators/matrix_text_decorator.rb +1 -1
  34. data/lib/pact_broker/api/decorators/pact_decorator.rb +1 -1
  35. data/lib/pact_broker/api/decorators/pacticipant_collection_decorator.rb +2 -2
  36. data/lib/pact_broker/api/decorators/pacticipant_decorator.rb +2 -1
  37. data/lib/pact_broker/api/decorators/pacts_for_verification_query_decorator.rb +4 -1
  38. data/lib/pact_broker/api/decorators/pagination_links.rb +6 -6
  39. data/lib/pact_broker/api/decorators/runtime_error_problem_json_decorator.rb +4 -4
  40. data/lib/pact_broker/api/decorators/validation_errors_problem_json_decorator.rb +6 -6
  41. data/lib/pact_broker/api/decorators/verifiable_pact_decorator.rb +4 -4
  42. data/lib/pact_broker/api/decorators/webhook_decorator.rb +2 -3
  43. data/lib/pact_broker/api/decorators/webhook_execution_result_decorator.rb +5 -12
  44. data/lib/pact_broker/api/resources/all_webhooks.rb +5 -11
  45. data/lib/pact_broker/api/resources/base_resource.rb +3 -20
  46. data/lib/pact_broker/api/resources/branch_version.rb +3 -3
  47. data/lib/pact_broker/api/resources/can_i_deploy.rb +4 -19
  48. data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_branch_to_environment.rb +1 -4
  49. data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_tag_to_tag.rb +0 -2
  50. data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_tag_to_tag_badge.rb +1 -2
  51. data/lib/pact_broker/api/resources/currently_deployed_versions_for_environment.rb +2 -2
  52. data/lib/pact_broker/api/resources/currently_supported_versions_for_environment.rb +2 -2
  53. data/lib/pact_broker/api/resources/dashboard.rb +3 -3
  54. data/lib/pact_broker/api/resources/deployed_version.rb +1 -1
  55. data/lib/pact_broker/api/resources/deployed_versions_for_version_and_environment.rb +2 -2
  56. data/lib/pact_broker/api/resources/environment.rb +1 -1
  57. data/lib/pact_broker/api/resources/environments.rb +2 -2
  58. data/lib/pact_broker/api/resources/error_handling_methods.rb +2 -2
  59. data/lib/pact_broker/api/resources/integrations.rb +1 -1
  60. data/lib/pact_broker/api/resources/label.rb +1 -1
  61. data/lib/pact_broker/api/resources/latest_pact.rb +2 -2
  62. data/lib/pact_broker/api/resources/latest_pacts.rb +1 -1
  63. data/lib/pact_broker/api/resources/latest_verifications_for_consumer_version.rb +1 -1
  64. data/lib/pact_broker/api/resources/matrix.rb +2 -2
  65. data/lib/pact_broker/api/resources/matrix_for_consumer_and_provider.rb +1 -1
  66. data/lib/pact_broker/api/resources/pact.rb +7 -4
  67. data/lib/pact_broker/api/resources/pact_triggered_webhooks.rb +1 -1
  68. data/lib/pact_broker/api/resources/pact_versions.rb +1 -1
  69. data/lib/pact_broker/api/resources/pact_webhooks.rb +7 -14
  70. data/lib/pact_broker/api/resources/pact_webhooks_status.rb +6 -2
  71. data/lib/pact_broker/api/resources/pacticipant.rb +1 -1
  72. data/lib/pact_broker/api/resources/pacticipant_webhooks.rb +7 -5
  73. data/lib/pact_broker/api/resources/pacticipants.rb +2 -2
  74. data/lib/pact_broker/api/resources/pacticipants_for_label.rb +1 -1
  75. data/lib/pact_broker/api/resources/previous_distinct_pact_version.rb +1 -1
  76. data/lib/pact_broker/api/resources/provider_pacts.rb +1 -1
  77. data/lib/pact_broker/api/resources/provider_pacts_for_verification.rb +4 -13
  78. data/lib/pact_broker/api/resources/publish_contracts.rb +8 -3
  79. data/lib/pact_broker/api/resources/released_version.rb +1 -1
  80. data/lib/pact_broker/api/resources/released_versions_for_version_and_environment.rb +2 -2
  81. data/lib/pact_broker/api/resources/tag.rb +1 -1
  82. data/lib/pact_broker/api/resources/tagged_pact_versions.rb +1 -1
  83. data/lib/pact_broker/api/resources/triggered_webhook_logs.rb +2 -2
  84. data/lib/pact_broker/api/resources/verification.rb +2 -2
  85. data/lib/pact_broker/api/resources/verification_triggered_webhooks.rb +1 -1
  86. data/lib/pact_broker/api/resources/verifications.rb +4 -6
  87. data/lib/pact_broker/api/resources/version.rb +1 -1
  88. data/lib/pact_broker/api/resources/versions.rb +1 -1
  89. data/lib/pact_broker/api/resources/webhook.rb +7 -6
  90. data/lib/pact_broker/api/resources/webhook_execution.rb +6 -4
  91. data/lib/pact_broker/api.rb +3 -12
  92. data/lib/pact_broker/certificates/certificate.rb +1 -0
  93. data/lib/pact_broker/config/setting.rb +1 -0
  94. data/lib/pact_broker/contracts/service.rb +1 -0
  95. data/lib/pact_broker/date_helper.rb +1 -1
  96. data/lib/pact_broker/db/clean_incremental.rb +1 -1
  97. data/lib/pact_broker/db/delete_overwritten_data.rb +6 -2
  98. data/lib/pact_broker/deployments/currently_deployed_version_id.rb +2 -0
  99. data/lib/pact_broker/deployments/deployed_version.rb +2 -0
  100. data/lib/pact_broker/deployments/deployed_version_service.rb +5 -1
  101. data/lib/pact_broker/deployments/environment.rb +2 -0
  102. data/lib/pact_broker/deployments/environment_service.rb +4 -3
  103. data/lib/pact_broker/deployments/released_version.rb +2 -0
  104. data/lib/pact_broker/deployments/released_version_service.rb +4 -0
  105. data/lib/pact_broker/diagnostic/resources/base_resource.rb +1 -1
  106. data/lib/pact_broker/doc/views/index/publish-contracts.markdown +5 -5
  107. data/lib/pact_broker/domain/label.rb +1 -0
  108. data/lib/pact_broker/domain/tag.rb +2 -0
  109. data/lib/pact_broker/domain/verification.rb +1 -1
  110. data/lib/pact_broker/domain/version.rb +4 -1
  111. data/lib/pact_broker/domain/webhook.rb +1 -1
  112. data/lib/pact_broker/index/service.rb +1 -1
  113. data/lib/pact_broker/integrations/integration.rb +1 -0
  114. data/lib/pact_broker/locale/en.yml +35 -14
  115. data/lib/pact_broker/matrix/query_ids.rb +4 -4
  116. data/lib/pact_broker/matrix/resolved_selector.rb +6 -1
  117. data/lib/pact_broker/matrix/service.rb +1 -0
  118. data/lib/pact_broker/messages.rb +5 -1
  119. data/lib/pact_broker/pacticipants/repository.rb +12 -3
  120. data/lib/pact_broker/pacticipants/service.rb +7 -0
  121. data/lib/pact_broker/pacts/pact_params.rb +6 -17
  122. data/lib/pact_broker/pacts/pact_version.rb +1 -0
  123. data/lib/pact_broker/policies.rb +4 -4
  124. data/lib/pact_broker/test/http_test_data_builder.rb +46 -2
  125. data/lib/pact_broker/ui/app.rb +2 -2
  126. data/lib/pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version.rb +1 -1
  127. data/lib/pact_broker/verifications/pact_version_provider_tag_successful_verification.rb +1 -0
  128. data/lib/pact_broker/verifications/service.rb +0 -6
  129. data/lib/pact_broker/version.rb +1 -1
  130. data/lib/pact_broker/versions/branch.rb +1 -0
  131. data/lib/pact_broker/versions/branch_head.rb +2 -1
  132. data/lib/pact_broker/versions/branch_version.rb +11 -0
  133. data/lib/pact_broker/webhooks/execution.rb +1 -1
  134. data/lib/pact_broker/webhooks/repository.rb +1 -1
  135. data/lib/pact_broker/webhooks/service.rb +3 -25
  136. data/lib/pact_broker/webhooks/triggered_webhook.rb +1 -0
  137. data/lib/pact_broker/webhooks/webhook_event.rb +1 -0
  138. data/lib/pact_broker/webmachine.rb +22 -0
  139. data/lib/rack/pact_broker/invalid_uri_protection.rb +1 -1
  140. data/lib/rack/pact_broker/use_when.rb +6 -5
  141. data/lib/sequel/plugins/age.rb +13 -0
  142. data/lib/webmachine/application_monkey_patch.rb +5 -0
  143. data/lib/webmachine/describe_routes.rb +35 -8
  144. data/lib/webmachine/render_error_monkey_patch.rb +1 -1
  145. data/pact_broker.gemspec +7 -17
  146. metadata +65 -67
  147. data/lib/pact/doc/README.md +0 -5
  148. data/lib/pact_broker/api/contracts/dry_validation_predicates.rb +0 -36
  149. data/lib/pact_broker/api/contracts/dry_validation_workarounds.rb +0 -39
  150. data/lib/pact_broker/api/contracts/pacticipant_name_contract.rb +0 -24
  151. data/lib/pact_broker/api/contracts/pacticipant_name_validation.rb +0 -30
  152. data/lib/pact_broker/api/contracts/request_validations.rb +0 -33
  153. data/lib/pact_broker/api/resources/webhook_resource_methods.rb +0 -17
  154. data/lib/pact_broker/matrix/can_i_deploy_query_schema.rb +0 -46
@@ -24,10 +24,12 @@ module PactBroker
24
24
  VERSION_COLUMNS = [:id, :number, :repository_ref, :pacticipant_id, :order, :created_at, :updated_at, :build_url]
25
25
 
26
26
  class Version < Sequel::Model(Sequel::Model.db[:versions].select(*VERSION_COLUMNS.collect{ | column | Sequel.qualify(:versions, column) }))
27
+ set_primary_key :id
28
+
27
29
  plugin :timestamps, update_on_create: true
30
+ plugin :age
28
31
  plugin :upsert, { identifying_columns: [:pacticipant_id, :number], ignore_columns_on_update: [:id, :created_at, :order] }
29
32
 
30
- set_primary_key :id
31
33
  one_to_many :pact_publications, order: :revision_number, class: "PactBroker::Pacts::PactPublication", key: :consumer_version_id
32
34
  associate(:many_to_one, :pacticipant, :class => "PactBroker::Domain::Pacticipant", :key => :pacticipant_id, :primary_key => :id)
33
35
  one_to_many :tags, :reciprocal => :version, order: :created_at
@@ -41,6 +43,7 @@ module PactBroker
41
43
  end
42
44
 
43
45
  one_to_many :deployed_versions, class: "PactBroker::Deployments::DeployedVersion", key: :version_id, primary_key: :id, order: [:created_at, :id]
46
+ one_to_many :released_versions, class: "PactBroker::Deployments::ReleasedVersion", key: :version_id, primary_key: :id, order: [:created_at, :id]
44
47
 
45
48
  many_to_one :latest_version_for_pacticipant, read_only: true, key: :id,
46
49
  class: Version,
@@ -50,7 +50,7 @@ module PactBroker
50
50
  def execute pact, verification, event_context, options
51
51
  logger.info "Executing #{self} event_context=#{event_context}"
52
52
  template_params = template_parameters(pact, verification, event_context, options)
53
- webhook_request = request.build(template_params, options.slice(:user_agent, :disable_ssl_verification, :cert_store))
53
+ webhook_request = request.build(template_params, **options.slice(:user_agent, :disable_ssl_verification, :cert_store))
54
54
  http_response, error = execute_request(webhook_request)
55
55
  success = success?(http_response, options)
56
56
  http_request = webhook_request.http_request
@@ -109,7 +109,7 @@ module PactBroker
109
109
  # rubocop: disable Metrics/CyclomaticComplexity
110
110
  def self.latest_verification_for_pseudo_branch(pact_publication, is_overall_latest, latest_verifications_for_cv_tags, tags_option, options)
111
111
  if options[:view] == "branch" || (options[:view] == "all" && pact_publication.consumer_version.branch_heads.any?)
112
- pact_publication.latest_verification || pact_publication.latest_verification_for_consumer_branches
112
+ pact_publication.latest_verification || pact_publication.latest_verification_for_consumer_branches(forbid_lazy_load: false)
113
113
  elsif tags_option == true
114
114
  latest_verifications_for_cv_tags
115
115
  .select{ | v | v.consumer_id == pact_publication.consumer_id && v.provider_id == pact_publication.provider_id && pact_publication.head_pact_tags.collect(&:name).include?(v.consumer_version_tag_name) }
@@ -8,6 +8,7 @@ require "pact_broker/verifications/latest_verification_for_consumer_and_provider
8
8
  module PactBroker
9
9
  module Integrations
10
10
  class Integration < Sequel::Model(Sequel::Model.db[:integrations].select(:id, :consumer_id, :provider_id))
11
+ set_primary_key :id
11
12
  plugin :insert_ignore, identifying_columns: [:consumer_id, :provider_id]
12
13
  associate(:many_to_one, :consumer, :class => "PactBroker::Domain::Pacticipant", :key => :consumer_id, :primary_key => :id)
13
14
  associate(:many_to_one, :provider, :class => "PactBroker::Domain::Pacticipant", :key => :provider_id, :primary_key => :id)
@@ -2,17 +2,10 @@ en:
2
2
  errors:
3
3
  not_blank?: "can't be blank"
4
4
  filled?: "can't be blank"
5
- valid_method?: "is not a recognised HTTP method"
6
5
  valid_url?: "is not a valid URL eg. http://example.org"
7
6
  base64?: "is not valid Base64"
8
- valid_version_number?: "Version number '%{value}' cannot be parsed to a version number. The expected format (unless this configuration has been overridden) is a semantic version. eg. 1.3.0 or 2.0.4.rc1"
9
- name_in_path_matches_name_in_pact?: "does not match %{left} name in path ('%{right}')."
10
- valid_consumer_version_number?: "Consumer version number '%{value}' cannot be parsed to a version number. The expected format (unless this configuration has been overridden) is a semantic version. eg. 1.3.0 or 2.0.4.rc1"
11
- non_templated_host?: "cannot have a template parameter in the host"
12
- pacticipant_exists?: "does not match an existing pacticipant"
13
7
  single_line?: "cannot contain multiple lines"
14
8
  no_spaces?: "cannot contain spaces"
15
- environment_with_name_exists?: "with name '%{value}' does not exist"
16
9
  none?: "cannot be provided"
17
10
 
18
11
  pact_broker:
@@ -68,33 +61,61 @@ en:
68
61
  version_branch: Configure the version branch to be the value of your repository branch.
69
62
  errors:
70
63
  validation:
71
- blank: "cannot be blank."
64
+ no_spaces: "cannot contain spaces"
65
+ single_line: "cannot contain multiple lines"
66
+ environment_not_found: "with name '%{value}' does not exist"
67
+ blank: "cannot be blank"
68
+ cannot_be_provided_at_same_time: "%{name_1} and %{name_2} cannot be provided at the same time"
69
+ blank_with_name: "%{name} cannot be blank"
72
70
  attribute_missing: "Missing required attribute '%{attribute}'"
73
71
  invalid_http_method: "Invalid HTTP method '%{method}'"
74
72
  invalid_url: "Invalid URL '%{url}'. Expected format: http://example.org"
75
73
  pact_missing_pacticipant_name: "was not found at expected path $.%{pacticipant}.name in the submitted pact file."
76
- pact_content_modification_not_allowed: "Cannot change the content of the pact for %{consumer_name} version %{consumer_version_number} and provider %{provider_name}, as race conditions will cause unreliable results for can-i-deploy. Each pact must be published with a unique consumer version number. For more information see https://docs.pact.io/go/versioning"
74
+ pact_content_modification_not_allowed: "Cannot change the content of the pact for %{consumer_name} version %{consumer_version_number} and provider %{provider_name}, as race conditions will cause unreliable results for can-i-deploy. Each pact must be published with a unique consumer version number. Some Pact libraries generate random data when a concrete value for a type matcher is not specified, and this can cause the contract to mutate - ensure you have given example values for all type matchers. For more information see https://docs.pact.io/go/versioning"
77
75
  consumer_version_number_missing: "Please specify the consumer version number by setting the X-Pact-Consumer-Version header."
78
76
  consumer_version_number_header_invalid: "X-Pact-Consumer-Version '%{consumer_version_number}' cannot be parsed to a version number. The expected format (unless this configuration has been overridden) is a semantic version. eg. 1.3.0 or 2.0.4.rc1"
79
- consumer_version_number_invalid: "Consumer version number '%{consumer_version_number}' cannot be parsed to a version number. The expected format (unless this configuration has been overridden) is a semantic version. eg. 1.3.0 or 2.0.4.rc1"
80
77
  pacticipant_name_mismatch: "in pact ('%{name_in_pact}') does not match %{pacticipant} name in path ('%{name}')."
81
- consumer_name_in_content_mismatch_pacticipant_name: "consumer name in contract content ('%{consumer_name_in_content}') must match pacticipantName ('%{pacticipant_name}')"
82
78
  consumer_name_in_contract_mismatch_pacticipant_name: "consumerName ('%{consumer_name_in_contract}') must match pacticipantName ('%{pacticipant_name}')"
83
- provider_name_in_content_mismatch: "provider name in contract content ('%{provider_name_in_content}') must match providerName ('%{provider_name}') in contracts"
79
+ consumer_name_in_content_mismatch: "consumer name in contract content ('%{consumer_name_in_content}') must match consumerName in contract params ('%{consumer_name}')"
80
+ provider_name_in_content_mismatch: "provider name in contract content ('%{provider_name_in_content}') must match providerName in contract params ('%{provider_name}')"
84
81
  connection_encoding_not_utf8: "The Sequel connection encoding (%{encoding}) is strongly recommended to be \"utf8\". If you need to set it to %{encoding} for some particular reason, then disable this check by setting config.validate_database_connection_config = false"
85
82
  invalid_webhook_uuid: The UUID can only contain the characters A-Z, a-z, 0-9, _ and -, and must be 16 or more characters.
86
83
  pacticipant_not_found: No pacticipant with name '%{name}' found
87
- environment_name_must_be_unique: Another environment with name '%{name}' already exists.
84
+ environment_name_must_be_unique: "name '%{name}' is already used by an existing environment."
88
85
  must_specify_environment_or_tag: Must specify either an environment or a 'to' tag.
89
86
  cannot_specify_tag_and_environment: Cannot specify both a 'to' tag and an environment.
90
87
  cannot_specify_latest_and_environment: Cannot specify both latest=true and an environment.
91
88
  cannot_specify_more_than_one_destination_identifier: Cannot specify more than one of tag, environment and mainBranch.
92
89
  environment_with_name_not_found: "Environment with name '%{name}' does not exist"
93
90
  cannot_modify_version_branch: "The branch for a pacticipant version cannot be changed once set (currently '%{old_branch}', proposed value '%{new_branch}'). Your pact publication/verification publication configurations may be in conflict with each other if you are seeing this error. If the current branch value is incorrect, you must delete the pacticipant version resource at %{version_url} and publish the pacts/verification results again with a consistent branch name."
94
- invalid_content_for_content_type: "The content could not be parsed as %{content_type}"
91
+ invalid_content_for_content_type: "content could not be parsed as %{content_type}"
95
92
  cannot_set_currently_deployed_true: The currentlyDeployed property cannot be set back to true. Please record a new deployment.
96
93
  cannot_set_currently_supported_true: The currentlySupported property cannot be set back to true. Please record a new deployment.
97
94
  invalid_limit: The limit must be 1 or greater.
95
+ pacts_for_verification_selector_fallback_tag: "fallbackTag can only be set if latest is true"
96
+ pacts_for_verification_selector_matching_branch_requires_provider_version_branch: the providerVersionBranch must be specified when the selector matchingBranch=true is used
97
+ pacts_for_verification_selector_tag_and_branch_disallowed: "cannot specify both a tag and a branch"
98
+ pacts_for_verification_selector_fallback_tag_requires_tag: "a tag must be specified when a fallbackTag is specified"
99
+ pacts_for_verification_selector_fallback_branch_requires_branch: "a branch must be specified when a fallbackBranch is specified"
100
+ pacts_for_verification_selector_branch_and_latest_false_disallowed: cannot specify a branch with latest=false
101
+ pacts_for_verification_selector_main_branch_and_latest_false_disallowed: cannot specify mainBranch=true with latest=false
102
+ pacts_for_verification_selector_fallback_branch_and_latest_false_disallowed: fallbackBranch can only be set if latest is true
103
+ pacts_for_verification_selector_required_params_missing: must specify a value for environment or tag or branch, or specify mainBranch=true, matchingBranch=true, latest=true, deployed=true, released=true or deployedOrReleased=true
104
+ pacts_for_verification_selector_main_branch_with_other_param_disallowed: cannot specify mainBranch=true with any other criteria apart from consumer
105
+ pacts_for_verification_selector_matching_branch_with_other_param_disallowed: cannot specify matchingBranch=true with any other criteria apart from consumer
106
+ pacts_for_verification_selector_deployed_and_released_disallowed: cannot specify both deployed=true and released=true
107
+ pacts_for_verification_selector_deployed_and_deployed_or_released_disallowed: cannot specify both deployed=true and deployedOrReleased=true
108
+ pacts_for_verification_selector_released_and_deployed_or_released_disallowed: cannot specify both released=true and deployedOrReleased=true
109
+ pacts_for_verification_selector_provider_version_branch_empty: when pending or WIP pacts are enabled and there are no tags provided, the provider version branch must not be an empty string, as it is used in the calculations for WIP/pending. A value must be provided (recommended), or it must not be set at all.
110
+ pact_name_in_path_mismatch_name_in_pact: "name in pact '%{name_in_pact}' does not match name in URL path '%{name_in_path}'."
111
+ base64: "is not valid Base64"
112
+ non_utf_8_char_in_contract: "contract content has a non UTF-8 character at char %{char_number} and cannot be parsed as JSON. Fragment preceding invalid character is: '%{fragment}'"
113
+ invalid_consumer_version_number: "Consumer version number '%{value}' cannot be parsed to a version number. The expected format (unless this configuration has been overridden) is a semantic version. eg. 1.3.0 or 2.0.4.rc1"
114
+ invalid_version_number: "Version number '%{value}' cannot be parsed to a version number. The expected format (unless this configuration has been overridden) is a semantic version. eg. 1.3.0 or 2.0.4.rc1"
115
+ invalid_url: "is not a valid URL eg. http://example.org"
116
+ pacticipant_with_name_not_found: "does not match an existing pacticipant"
117
+ invalid_http_method: "is not a recognised HTTP method"
118
+ webhook_templated_host_not_allowed: "cannot have a template parameter in the host"
98
119
  duplicate_pacticipant: |
99
120
  This is the first time a pact has been published for "%{new_name}".
100
121
  The name "%{new_name}" is very similar to the following existing pacticipants:
@@ -17,10 +17,10 @@ module PactBroker
17
17
 
18
18
  def self.from_selectors(selectors)
19
19
  most_specific_criteria = selectors.collect(&:most_specific_criterion)
20
- all_pacticipant_ids = selectors.collect(&:pacticipant_id)
21
- specified_pacticipant_ids = selectors.select(&:specified?).collect(&:pacticipant_id)
22
- pacticipant_version_ids = collect_ids(most_specific_criteria, :pacticipant_version_id)
23
- pacticipant_ids = collect_ids(most_specific_criteria, :pacticipant_id)
20
+ all_pacticipant_ids = selectors.collect(&:pacticipant_id).uniq
21
+ specified_pacticipant_ids = selectors.select(&:specified?).collect(&:pacticipant_id).uniq
22
+ pacticipant_version_ids = collect_ids(most_specific_criteria, :pacticipant_version_id).uniq
23
+ pacticipant_ids = collect_ids(most_specific_criteria, :pacticipant_id).uniq
24
24
  QueryIds.new(all_pacticipant_ids, specified_pacticipant_ids, pacticipant_ids, pacticipant_version_ids)
25
25
  end
26
26
 
@@ -1,12 +1,17 @@
1
+ require "pact_broker/hash_refinements"
2
+
1
3
  # A selector with the pacticipant id, name, version number, and version id set
2
4
  # This is created from either specified or inferred data, based on the user's query
3
5
  # eg.
4
6
  # can-i-deploy --pacticipant Foo --version 1 (this is a specified selector)
5
7
  # --to prod (this is used to create inferred selectors)
8
+
6
9
  module PactBroker
7
10
  module Matrix
8
11
  class ResolvedSelector < Hash
9
12
 
13
+ using PactBroker::HashRefinements
14
+
10
15
  # A version ID of -1 will not match any rows, which is what we want to ensure that
11
16
  # no matrix rows are returned for a version that does not exist.
12
17
  NULL_VERSION_ID = -1
@@ -124,7 +129,7 @@ module PactBroker
124
129
  end
125
130
 
126
131
  def only_pacticipant_name_specified?
127
- !!pacticipant_name && !branch && !tag && !latest? && !pacticipant_version_number && !main_branch?
132
+ !!pacticipant_name && self[:original_selector].without(:pacticipant_name).none?{ |_key, value| value }
128
133
  end
129
134
 
130
135
  def latest_tagged?
@@ -52,6 +52,7 @@ module PactBroker
52
52
  end
53
53
  end
54
54
 
55
+ # TODO create a proper contract for this
55
56
  # rubocop: disable Metrics/CyclomaticComplexity
56
57
  def validate_selectors selectors, options = {}
57
58
  error_messages = []
@@ -16,13 +16,17 @@ module PactBroker
16
16
  # variables to interpolate.
17
17
  # @return [String] the interpolated string
18
18
  def message(key, options={})
19
- ::I18n.t(key, { :scope => :pact_broker }.merge(options))
19
+ ::I18n.t(key, **{ :scope => :pact_broker }.merge(options))
20
20
  end
21
21
 
22
22
  def validation_message key, options = {}
23
23
  message("errors.validation." + key, options)
24
24
  end
25
25
 
26
+ def validation_message_at_index key, index, options = {}
27
+ message("errors.validation." + key, options).chomp(".") + " (at index #{index})"
28
+ end
29
+
26
30
  def pluralize(word, count)
27
31
  if count == 1
28
32
  word
@@ -2,13 +2,15 @@ require "sequel"
2
2
  require "pact_broker/domain/pacticipant"
3
3
  require "pact_broker/repositories/helpers"
4
4
  require "pact_broker/error"
5
+ require "pact_broker/repositories/scopes"
5
6
 
6
7
  module PactBroker
7
8
  module Pacticipants
8
9
  class Repository
9
10
 
10
- include PactBroker::Repositories::Helpers
11
11
  include PactBroker::Repositories
12
+ include PactBroker::Repositories::Helpers
13
+ include PactBroker::Repositories::Scopes
12
14
 
13
15
  def find_by_name name
14
16
  pacticipants = PactBroker::Domain::Pacticipant.where(name_like(:name, name)).all
@@ -22,6 +24,13 @@ module PactBroker
22
24
  pacticipant
23
25
  end
24
26
 
27
+ # @param [Array<String>] the array of names by which to find the pacticipants
28
+ def find_by_names(names)
29
+ return [] if names.empty?
30
+ name_likes = names.collect{ | name | name_like(:name, name) }
31
+ scope_for(PactBroker::Domain::Pacticipant).where(Sequel.|(*name_likes)).all
32
+ end
33
+
25
34
  def find_by_id id
26
35
  PactBroker::Domain::Pacticipant.where(id: id).single_record
27
36
  end
@@ -31,7 +40,7 @@ module PactBroker
31
40
  end
32
41
 
33
42
  def find(options = {}, pagination_options = {})
34
- query = PactBroker::Domain::Pacticipant.select_all_qualified
43
+ query = scope_for(PactBroker::Domain::Pacticipant).select_all_qualified
35
44
  query = query.label(options[:label_name]) if options[:label_name]
36
45
  query.order_ignore_case(Sequel[:pacticipants][:name]).eager(:labels).eager(:latest_version).all_with_pagination_options(pagination_options)
37
46
  end
@@ -96,7 +105,7 @@ module PactBroker
96
105
  def search_by_name(pacticipant_name)
97
106
  terms = pacticipant_name.split.map { |v| v.gsub("_", "\\_") }
98
107
  string_match_query = Sequel.|( *terms.map { |term| Sequel.ilike(Sequel[:pacticipants][:name], "%#{term}%") })
99
- PactBroker::Domain::Pacticipant.where(string_match_query)
108
+ scope_for(PactBroker::Domain::Pacticipant).where(string_match_query)
100
109
  end
101
110
 
102
111
  def set_main_branch(pacticipant, main_branch)
@@ -40,6 +40,13 @@ module PactBroker
40
40
  pacticipant_repository.find_by_name(name)
41
41
  end
42
42
 
43
+ # Used by pf
44
+ # @param [Array<String>]
45
+ # @return [Array<PactBroker::Domain::Pacticipant>]
46
+ def self.find_pacticipants_by_names(names)
47
+ pacticipant_repository.find_by_names(names)
48
+ end
49
+
43
50
  def self.find_pacticipant_by_name!(name)
44
51
  pacticipant_repository.find_by_name!(name)
45
52
  end
@@ -81,24 +81,13 @@ module PactBroker
81
81
  self[:provider_name_in_pact]
82
82
  end
83
83
 
84
- def consumer
85
- PacticipantName.new(consumer_name, consumer_name_in_pact, "consumer")
84
+ def to_hash_for_validation
85
+ {
86
+ consumer_version_number: consumer_version_number,
87
+ consumer: { name: consumer_name, name_in_pact: consumer_name_in_pact },
88
+ provider: { name: provider_name, name_in_pact: provider_name_in_pact }
89
+ }
86
90
  end
87
-
88
- def provider
89
- PacticipantName.new(provider_name, provider_name_in_pact, "provider")
90
- end
91
-
92
- class PacticipantName < Struct.new(:name, :name_in_pact, :pacticipant)
93
- def message_args
94
- {
95
- name: name,
96
- name_in_pact: name_in_pact,
97
- pacticipant: pacticipant
98
- }
99
- end
100
- end
101
-
102
91
  end
103
92
  end
104
93
  end
@@ -7,6 +7,7 @@ module PactBroker
7
7
  module Pacts
8
8
  class PactVersion < Sequel::Model(:pact_versions)
9
9
  include PactVersionAssociationLoaders
10
+ set_primary_key :id
10
11
 
11
12
  plugin :timestamps
12
13
  plugin :upsert, identifying_columns: [:consumer_id, :provider_id, :sha]
@@ -7,19 +7,19 @@ module PactBroker
7
7
  @resource = resource
8
8
  end
9
9
 
10
- def update?
10
+ def read?
11
11
  true
12
12
  end
13
13
 
14
- def delete?
14
+ def update?
15
15
  true
16
16
  end
17
17
 
18
- def create?
18
+ def delete?
19
19
  true
20
20
  end
21
21
 
22
- def view?
22
+ def create?
23
23
  true
24
24
  end
25
25
 
@@ -3,20 +3,59 @@ require "logger"
3
3
  require "erb"
4
4
  require "yaml"
5
5
  require "base64"
6
+ require "securerandom"
6
7
 
7
8
  module PactBroker
8
9
  module Test
9
10
  class HttpTestDataBuilder
10
11
 
12
+ class SetRequestId < Faraday::Middleware
13
+ def initialize(app, correlation_id, logger)
14
+ super(app)
15
+ @correlation_id = correlation_id
16
+ @logger = logger
17
+ end
18
+
19
+ def on_request(env)
20
+ request_id = "#{@correlation_id}-#{Time.now.to_f.to_s[7... -1]}"
21
+ env.request_headers["X-Request-Id"] = request_id
22
+ @logger.info("X-Request-Id: #{request_id}")
23
+ end
24
+ end
25
+
26
+ class LogRequestLength < Faraday::Middleware
27
+ def initialize(app, logger)
28
+ super(app)
29
+ @app = app
30
+ @logger = logger
31
+ end
32
+
33
+ def call(env)
34
+ starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
35
+ response = @app.call(env)
36
+ ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
37
+ elapsed = ending - starting
38
+ @logger.info "Response time: #{elapsed}"
39
+ response
40
+ end
41
+ end
42
+
11
43
  attr_reader :client, :last_consumer_name, :last_provider_name, :last_consumer_version_number, :last_provider_version_number, :last_provider_version_tag, :last_provider_version_branch
12
44
 
13
45
  def initialize(pact_broker_base_url, auth = {})
46
+ @correlation_id = SecureRandom.hex(10)
47
+
48
+ stream = ENV["DEBUG"] == "true" ? $stdout : StringIO.new
49
+ logger = ::Logger.new(stream)
50
+
14
51
  @client = Faraday.new(url: pact_broker_base_url) do |faraday|
52
+ faraday.use LogRequestLength, logger
53
+ faraday.use SetRequestId, @correlation_id, logger
15
54
  faraday.request :json
16
55
  faraday.response :json, :content_type => /\bjson$/
17
56
  if ENV["DEBUG"] == "true"
18
- faraday.response :logger, ::Logger.new($stdout), headers: false, body: true do | logger |
19
- logger.filter(/(Authorization: ).*/,'\1[REMOVED]')
57
+ faraday.response :logger, logger, headers: false, body: true do | l |
58
+ l.filter(/(Authorization: ).*/,'\1[REMOVED]')
20
59
  end
21
60
  end
22
61
  faraday.basic_auth(auth[:username], auth[:password]) if auth[:username]
@@ -30,6 +69,11 @@ module PactBroker
30
69
  self
31
70
  end
32
71
 
72
+ def print_correlation_id
73
+ puts "Correlation ID is #{@correlation_id}"
74
+ self
75
+ end
76
+
33
77
  def separate
34
78
  puts "\n=============================================================\n\n"
35
79
  end
@@ -26,7 +26,7 @@ module PactBroker
26
26
  class App
27
27
 
28
28
  def initialize
29
- @app = ::Rack::Builder.new {
29
+ @app = ::Rack::Builder.new do
30
30
 
31
31
  map "/ui/relationships" do
32
32
  run PactBroker::UI::Controllers::Index
@@ -69,7 +69,7 @@ module PactBroker
69
69
  use PathInfoFixer
70
70
  run PactBroker::UI::Controllers::Index
71
71
  end
72
- }
72
+ end
73
73
  end
74
74
 
75
75
  def call env
@@ -3,8 +3,8 @@ require "pact_broker/domain/verification"
3
3
  module PactBroker
4
4
  module Verifications
5
5
  class LatestVerificationIdForPactVersionAndProviderVersion < Sequel::Model(:latest_verification_id_for_pact_version_and_provider_version)
6
- unrestrict_primary_key
7
6
  set_primary_key [:pact_version_id, :provider_version_id]
7
+ unrestrict_primary_key
8
8
 
9
9
  plugin :upsert, identifying_columns: [:pact_version_id, :provider_version_id]
10
10
 
@@ -5,6 +5,7 @@ require "pact_broker/domain/verification"
5
5
  module PactBroker
6
6
  module Verifications
7
7
  class PactVersionProviderTagSuccessfulVerification < Sequel::Model
8
+ set_primary_key :id
8
9
  plugin :insert_ignore, identifying_columns: [:pact_version_id, :provider_version_tag_name, :wip]
9
10
  end
10
11
  end
@@ -57,12 +57,6 @@ module PactBroker
57
57
  verification_repository.delete(verification.id)
58
58
  end
59
59
 
60
- def errors params
61
- contract = PactBroker::Api::Contracts::VerificationContract.new(PactBroker::Domain::Verification.new)
62
- contract.validate(params)
63
- contract.errors
64
- end
65
-
66
60
  def find params
67
61
  verification_repository.find(params.fetch(:consumer_name), params.fetch(:provider_name), params.fetch(:pact_version_sha), params.fetch(:verification_number))
68
62
  end
@@ -1,3 +1,3 @@
1
1
  module PactBroker
2
- VERSION = "2.106.0"
2
+ VERSION = "2.107.0"
3
3
  end
@@ -4,6 +4,7 @@ require "pact_broker/repositories/helpers"
4
4
  module PactBroker
5
5
  module Versions
6
6
  class Branch < Sequel::Model(:branches)
7
+ set_primary_key :id
7
8
  plugin :timestamps, update_on_create: true
8
9
  plugin :insert_ignore, identifying_columns: [:name, :pacticipant_id]
9
10
 
@@ -4,10 +4,11 @@ require "pact_broker/repositories/helpers"
4
4
  module PactBroker
5
5
  module Versions
6
6
  class BranchHead < Sequel::Model
7
- plugin :upsert, identifying_columns: [:branch_id]
8
7
  set_primary_key :branch_id
9
8
  unrestrict_primary_key
10
9
 
10
+ plugin :upsert, identifying_columns: [:branch_id]
11
+
11
12
  associate(:many_to_one, :branch, :class => "PactBroker::Versions::Branch", :key => :branch_id, :primary_key => :id)
12
13
  associate(:many_to_one, :branch_version, :class => "PactBroker::Versions::BranchVersion", :key => :branch_version_id, :primary_key => :id)
13
14
  associate(:many_to_one, :version, :class => "PactBroker::Domain::Version", :key => :version_id, :primary_key => :id)
@@ -4,6 +4,7 @@ require "pact_broker/repositories/helpers"
4
4
  module PactBroker
5
5
  module Versions
6
6
  class BranchVersion < Sequel::Model(:branch_versions)
7
+ set_primary_key :id
7
8
  plugin :timestamps, update_on_create: true
8
9
  plugin :insert_ignore, identifying_columns: [:branch_id, :version_id]
9
10
  plugin :upsert, identifying_columns: [:branch_id, :version_id]
@@ -38,6 +39,16 @@ module PactBroker
38
39
  def pacticipant
39
40
  branch.pacticipant
40
41
  end
42
+
43
+ # For Pactflow
44
+ def main_branch?
45
+ branch_name == branch.pacticipant.main_branch
46
+ end
47
+
48
+ # For Pactflow
49
+ def number_of_versions_from_head
50
+ @number_of_versions_from_head ||= BranchVersion.where(branch_id: branch_id).where(Sequel.lit("version_order > ?", version_order) ).count
51
+ end
41
52
  end
42
53
  end
43
54
  end
@@ -12,7 +12,7 @@ module PactBroker
12
12
  :logs,
13
13
  Sequel[:webhook_executions][:created_at])
14
14
  )
15
-
15
+ set_primary_key :id
16
16
  plugin :timestamps
17
17
 
18
18
  dataset_module do
@@ -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