pact_broker 2.107.1 → 2.109.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +68 -0
  3. data/Gemfile +5 -6
  4. data/README.md +1 -0
  5. data/db/migrations/20230615_add_integrations_contract_data_updated_at.rb +13 -0
  6. data/db/migrations/20230616_set_integrations_contract_data_updated_at.rb +11 -0
  7. data/db/migrations/20231002_add_version_id_index_to_released_version.rb +21 -0
  8. data/db/migrations/20231003_add_version_id_index_to_deployed_version.rb +21 -0
  9. data/docs/CONFIGURATION.md +10 -0
  10. data/lib/pact_broker/api/contracts/base_contract.rb +2 -1
  11. data/lib/pact_broker/api/contracts/dry_validation_errors_formatter.rb +2 -0
  12. data/lib/pact_broker/api/contracts/pagination_query_params_schema.rb +19 -0
  13. data/lib/pact_broker/api/contracts/publish_contracts_contract_contract.rb +29 -18
  14. data/lib/pact_broker/api/decorators/base_decorator.rb +40 -1
  15. data/lib/pact_broker/api/decorators/branch_decorator.rb +35 -0
  16. data/lib/pact_broker/api/decorators/branch_version_decorator.rb +16 -0
  17. data/lib/pact_broker/api/decorators/configuration.rb +19 -0
  18. data/lib/pact_broker/api/decorators/custom_error_problem_json_decorator.rb +1 -1
  19. data/lib/pact_broker/api/decorators/decorator_context_creator.rb +47 -2
  20. data/lib/pact_broker/api/decorators/deployed_version_decorator.rb +2 -1
  21. data/lib/pact_broker/api/decorators/deployed_versions_decorator.rb +2 -2
  22. data/lib/pact_broker/api/decorators/dry_validation_errors_decorator.rb +32 -0
  23. data/lib/pact_broker/api/decorators/dry_validation_errors_problem_json_decorator.rb +24 -0
  24. data/lib/pact_broker/api/decorators/embedded_branch_version_decorator.rb +2 -2
  25. data/lib/pact_broker/api/decorators/embedded_deployed_version_decorator.rb +30 -0
  26. data/lib/pact_broker/api/decorators/embedded_error_problem_json_decorator.rb +84 -0
  27. data/lib/pact_broker/api/decorators/embedded_released_version_decorator.rb +27 -0
  28. data/lib/pact_broker/api/decorators/embedded_version_decorator.rb +0 -3
  29. data/lib/pact_broker/api/decorators/error_decorator.rb +30 -0
  30. data/lib/pact_broker/api/decorators/extended_pact_decorator.rb +6 -1
  31. data/lib/pact_broker/api/decorators/integration_decorator.rb +3 -2
  32. data/lib/pact_broker/api/decorators/integrations_decorator.rb +3 -0
  33. data/lib/pact_broker/api/decorators/notices_decorator.rb +11 -0
  34. data/lib/pact_broker/api/decorators/pact_pacticipant_decorator.rb +1 -5
  35. data/lib/pact_broker/api/decorators/pact_versions_decorator.rb +0 -1
  36. data/lib/pact_broker/api/decorators/pact_webhooks_status_decorator.rb +0 -1
  37. data/lib/pact_broker/api/decorators/pacticipant_branches_decorator.rb +32 -0
  38. data/lib/pact_broker/api/decorators/pacticipant_decorator.rb +11 -1
  39. data/lib/pact_broker/api/decorators/{pacticipant_collection_decorator.rb → pacticipants_decorator.rb} +8 -4
  40. data/lib/pact_broker/api/decorators/pagination_links.rb +2 -2
  41. data/lib/pact_broker/api/decorators/publish_contract_decorator.rb +6 -1
  42. data/lib/pact_broker/api/decorators/released_versions_decorator.rb +2 -2
  43. data/lib/pact_broker/api/decorators/runtime_error_problem_json_decorator.rb +2 -2
  44. data/lib/pact_broker/api/decorators/validation_errors_decorator.rb +30 -0
  45. data/lib/pact_broker/api/decorators/validation_errors_problem_json_decorator.rb +4 -6
  46. data/lib/pact_broker/api/decorators/version_decorator.rb +5 -3
  47. data/lib/pact_broker/api/decorators/versions_decorator.rb +24 -14
  48. data/lib/pact_broker/api/decorators/webhook_decorator.rb +1 -1
  49. data/lib/pact_broker/api/decorators/webhook_execution_result_decorator.rb +2 -0
  50. data/lib/pact_broker/api/middleware/configuration.rb +2 -0
  51. data/lib/pact_broker/api/pact_broker_urls.rb +18 -2
  52. data/lib/pact_broker/api/resources/after_reply.rb +15 -0
  53. data/lib/pact_broker/api/resources/all_webhooks.rb +3 -3
  54. data/lib/pact_broker/api/resources/badge_methods.rb +2 -1
  55. data/lib/pact_broker/api/resources/base_resource.rb +6 -4
  56. data/lib/pact_broker/api/resources/branch.rb +40 -0
  57. data/lib/pact_broker/api/resources/branch_versions.rb +59 -0
  58. data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_branch_to_environment_badge.rb +1 -1
  59. data/lib/pact_broker/api/resources/currently_deployed_versions_for_environment.rb +1 -1
  60. data/lib/pact_broker/api/resources/currently_supported_versions_for_environment.rb +1 -1
  61. data/lib/pact_broker/api/resources/dashboard.rb +10 -0
  62. data/lib/pact_broker/api/resources/deployed_versions_for_version_and_environment.rb +1 -1
  63. data/lib/pact_broker/api/resources/environment.rb +4 -0
  64. data/lib/pact_broker/api/resources/environments.rb +1 -1
  65. data/lib/pact_broker/api/resources/error_handler.rb +18 -52
  66. data/lib/pact_broker/api/resources/error_handling_methods.rb +40 -14
  67. data/lib/pact_broker/api/resources/error_response_generator.rb +23 -6
  68. data/lib/pact_broker/api/resources/event_methods.rb +15 -0
  69. data/lib/pact_broker/api/resources/filter_methods.rb +15 -0
  70. data/lib/pact_broker/api/resources/group.rb +11 -2
  71. data/lib/pact_broker/api/resources/index.rb +6 -0
  72. data/lib/pact_broker/api/resources/integrations.rb +18 -4
  73. data/lib/pact_broker/api/resources/latest_version.rb +2 -0
  74. data/lib/pact_broker/api/resources/pact.rb +16 -7
  75. data/lib/pact_broker/api/resources/pacticipant_branches.rb +67 -0
  76. data/lib/pact_broker/api/resources/pacticipants.rb +26 -7
  77. data/lib/pact_broker/api/resources/pacticipants_for_label.rb +2 -2
  78. data/lib/pact_broker/api/resources/pagination_methods.rb +11 -1
  79. data/lib/pact_broker/api/resources/publish_contracts.rb +1 -1
  80. data/lib/pact_broker/api/resources/verifications.rb +9 -4
  81. data/lib/pact_broker/api/resources/versions.rb +12 -0
  82. data/lib/pact_broker/api.rb +5 -0
  83. data/lib/pact_broker/app.rb +10 -9
  84. data/lib/pact_broker/application_context.rb +29 -25
  85. data/lib/pact_broker/async/after_reply.rb +30 -0
  86. data/lib/pact_broker/config/runtime_configuration.rb +9 -21
  87. data/lib/pact_broker/config/runtime_configuration_coercion_methods.rb +32 -2
  88. data/lib/pact_broker/config/runtime_configuration_database_methods.rb +1 -1
  89. data/lib/pact_broker/config/runtime_configuration_logging_methods.rb +15 -5
  90. data/lib/pact_broker/configuration.rb +29 -12
  91. data/lib/pact_broker/contracts/contract_to_publish.rb +4 -5
  92. data/lib/pact_broker/contracts/contracts_to_publish.rb +8 -0
  93. data/lib/pact_broker/contracts/service.rb +9 -3
  94. data/lib/pact_broker/dataset/page.rb +22 -0
  95. data/lib/pact_broker/dataset.rb +122 -0
  96. data/lib/pact_broker/db/data_migrations/set_contract_data_updated_at_for_integrations.rb +47 -0
  97. data/lib/pact_broker/db/migrate_data.rb +1 -0
  98. data/lib/pact_broker/db/models.rb +1 -1
  99. data/lib/pact_broker/deployments/currently_deployed_version_id.rb +2 -5
  100. data/lib/pact_broker/deployments/deployed_version.rb +3 -3
  101. data/lib/pact_broker/deployments/environment.rb +0 -2
  102. data/lib/pact_broker/deployments/released_version.rb +4 -5
  103. data/lib/pact_broker/doc/views/index/pacticipant-branch.markdown +25 -0
  104. data/lib/pact_broker/domain/label.rb +6 -3
  105. data/lib/pact_broker/domain/pact.rb +10 -5
  106. data/lib/pact_broker/domain/pacticipant.rb +4 -34
  107. data/lib/pact_broker/domain/tag.rb +4 -5
  108. data/lib/pact_broker/domain/verification.rb +2 -4
  109. data/lib/pact_broker/domain/version.rb +12 -19
  110. data/lib/pact_broker/errors/error_reporter.rb +30 -0
  111. data/lib/pact_broker/errors.rb +2 -15
  112. data/lib/pact_broker/events/subscriber.rb +12 -4
  113. data/lib/pact_broker/feature_toggle.rb +1 -1
  114. data/lib/pact_broker/groups/service.rb +38 -5
  115. data/lib/pact_broker/index/service.rb +1 -2
  116. data/lib/pact_broker/integrations/event_listener.rb +23 -0
  117. data/lib/pact_broker/integrations/integration.rb +24 -2
  118. data/lib/pact_broker/integrations/repository.rb +34 -1
  119. data/lib/pact_broker/integrations/service.rb +17 -18
  120. data/lib/pact_broker/labels/repository.rb +4 -8
  121. data/lib/pact_broker/locale/en.yml +5 -0
  122. data/lib/pact_broker/logging.rb +10 -0
  123. data/lib/pact_broker/matrix/every_row.rb +58 -40
  124. data/lib/pact_broker/matrix/integration_row.rb +95 -0
  125. data/lib/pact_broker/matrix/integrations_repository.rb +133 -0
  126. data/lib/pact_broker/matrix/matrix_row.rb +88 -0
  127. data/lib/pact_broker/matrix/matrix_row_dataset_module.rb +185 -0
  128. data/lib/pact_broker/matrix/matrix_row_instance_methods.rb +150 -0
  129. data/lib/pact_broker/matrix/matrix_row_verification_dataset_module.rb +83 -0
  130. data/lib/pact_broker/matrix/parse_query.rb +1 -0
  131. data/lib/pact_broker/matrix/repository.rb +62 -285
  132. data/lib/pact_broker/matrix/resolved_selector.rb +13 -4
  133. data/lib/pact_broker/matrix/resolved_selector_builder.rb +84 -0
  134. data/lib/pact_broker/matrix/resolved_selectors_builder.rb +39 -0
  135. data/lib/pact_broker/matrix/row_ignorer.rb +36 -0
  136. data/lib/pact_broker/matrix/selector_ignorer.rb +59 -0
  137. data/lib/pact_broker/matrix/selector_resolver.rb +130 -0
  138. data/lib/pact_broker/metrics/service.rb +4 -9
  139. data/lib/pact_broker/pacticipants/latest_version_for_pacticipant_eager_loader.rb +33 -0
  140. data/lib/pact_broker/pacticipants/repository.rb +7 -9
  141. data/lib/pact_broker/pacticipants/service.rb +2 -2
  142. data/lib/pact_broker/pacts/generate_sha.rb +9 -4
  143. data/lib/pact_broker/pacts/latest_pact_publication_id_for_consumer_version.rb +2 -4
  144. data/lib/pact_broker/pacts/metadata.rb +3 -1
  145. data/lib/pact_broker/pacts/pact_params.rb +1 -1
  146. data/lib/pact_broker/pacts/pact_publication.rb +23 -5
  147. data/lib/pact_broker/pacts/pact_publication_dataset_module.rb +5 -1
  148. data/lib/pact_broker/pacts/pact_version.rb +2 -3
  149. data/lib/pact_broker/pacts/pacts_for_verification_repository.rb +2 -5
  150. data/lib/pact_broker/pacts/placeholder_pact.rb +3 -1
  151. data/lib/pact_broker/pacts/repository.rb +12 -12
  152. data/lib/pact_broker/pacts/service.rb +12 -13
  153. data/lib/pact_broker/repositories.rb +9 -1
  154. data/lib/pact_broker/string_refinements.rb +4 -0
  155. data/lib/pact_broker/tags/head_pact_tags.rb +2 -5
  156. data/lib/pact_broker/tags/repository.rb +3 -7
  157. data/lib/pact_broker/test/test_data_builder.rb +57 -2
  158. data/lib/pact_broker/ui/controllers/base_controller.rb +4 -2
  159. data/lib/pact_broker/ui/controllers/groups.rb +2 -1
  160. data/lib/pact_broker/ui/view_models/matrix_line.rb +4 -4
  161. data/lib/pact_broker/ui/views/groups/show.html.erb +2 -1
  162. data/lib/pact_broker/ui.rb +20 -9
  163. data/lib/pact_broker/verifications/latest_verification_for_consumer_and_provider.rb +0 -3
  164. data/lib/pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version.rb +2 -4
  165. data/lib/pact_broker/verifications/repository.rb +2 -5
  166. data/lib/pact_broker/verifications/sequence.rb +1 -4
  167. data/lib/pact_broker/verifications/service.rb +4 -0
  168. data/lib/pact_broker/version.rb +1 -1
  169. data/lib/pact_broker/versions/branch.rb +2 -5
  170. data/lib/pact_broker/versions/branch_head.rb +0 -3
  171. data/lib/pact_broker/versions/branch_repository.rb +76 -0
  172. data/lib/pact_broker/versions/branch_service.rb +13 -25
  173. data/lib/pact_broker/versions/branch_version.rb +0 -3
  174. data/lib/pact_broker/versions/branch_version_repository.rb +17 -0
  175. data/lib/pact_broker/versions/repository.rb +19 -2
  176. data/lib/pact_broker/versions/sequence.rb +1 -3
  177. data/lib/pact_broker/versions/service.rb +4 -0
  178. data/lib/pact_broker/webhooks/execution.rb +3 -7
  179. data/lib/pact_broker/webhooks/job.rb +16 -7
  180. data/lib/pact_broker/webhooks/pact_and_verification_parameters.rb +2 -2
  181. data/lib/pact_broker/webhooks/repository.rb +0 -1
  182. data/lib/pact_broker/webhooks/trigger_service.rb +11 -12
  183. data/lib/pact_broker/webhooks/triggered_webhook.rb +3 -4
  184. data/lib/pact_broker/webhooks/webhook.rb +2 -2
  185. data/lib/pact_broker/webhooks/webhook_event.rb +2 -5
  186. data/lib/rack/pact_broker/add_cache_header.rb +14 -0
  187. data/lib/rack/pact_broker/application_context.rb +16 -0
  188. data/lib/rack/pact_broker/configurable_make_it_later.rb +1 -1
  189. data/lib/rack/pact_broker/invalid_uri_protection.rb +19 -3
  190. data/lib/webmachine/describe_routes.rb +55 -39
  191. data/lib/webmachine/render_error_monkey_patch.rb +13 -4
  192. data/pact_broker.gemspec +5 -5
  193. metadata +54 -31
  194. data/lib/pact_broker/api/decorators/decorator_context.rb +0 -22
  195. data/lib/pact_broker/matrix/query_builder.rb +0 -90
  196. data/lib/pact_broker/matrix/query_ids.rb +0 -40
  197. data/lib/pact_broker/matrix/quick_row.rb +0 -458
  198. data/lib/pact_broker/relationships/groupify.rb +0 -45
  199. data/lib/pact_broker/repositories/helpers.rb +0 -96
  200. data/lib/pact_broker/repositories/page.rb +0 -24
  201. data/lib/pact_broker/tags/tag_with_latest_flag.rb +0 -28
@@ -1,7 +1,7 @@
1
1
  require "forwardable"
2
+ require "pact_broker/dataset"
2
3
  require "pact_broker/domain/pact"
3
4
  require "pact_broker/pacts/pact_version"
4
- require "pact_broker/repositories/helpers"
5
5
  require "pact_broker/integrations/integration"
6
6
  require "pact_broker/tags/head_pact_tags"
7
7
  require "pact_broker/pacts/pact_publication_dataset_module"
@@ -52,16 +52,22 @@ module PactBroker
52
52
  plugin :timestamps, update_on_create: true
53
53
 
54
54
  dataset_module do
55
- include PactBroker::Repositories::Helpers
55
+ include PactBroker::Dataset
56
56
  include PactPublicationDatasetModule
57
57
  include PactPublicationCleanSelectorDatasetModule
58
58
  include PactPublicationWipDatasetModule
59
59
 
60
60
  def eager_for_domain_with_content
61
- eager(:tags, :consumer, :provider, :consumer_version, :pact_version)
61
+ eager(:tags, :consumer, :provider, :pact_version, { consumer_version: :branch_versions })
62
62
  end
63
63
  end
64
64
 
65
+ def with_version_branches_and_tags
66
+ consumer_version.tags
67
+ consumer_version.branch_versions
68
+ self
69
+ end
70
+
65
71
  def self.subtract(a, *b)
66
72
  b_ids = b.flat_map{ |pact_publications| pact_publications.collect(&:id) }
67
73
  a.reject{ |pact_publication| b_ids.include?(pact_publication.id) }
@@ -125,8 +131,9 @@ module PactBroker
125
131
  @latest_for_branch
126
132
  end
127
133
 
134
+ # rubocop:disable Metrics/CyclomaticComplexity
128
135
  def to_domain
129
- PactBroker::Domain::Pact.new(
136
+ attributes = {
130
137
  id: id,
131
138
  provider: provider,
132
139
  consumer: consumer,
@@ -139,8 +146,19 @@ module PactBroker
139
146
  created_at: created_at,
140
147
  head_tag_names: [],
141
148
  db_model: self
142
- )
149
+ }
150
+
151
+ if associations[:tags] || consumer_version.associations[:tags]
152
+ attributes[:consumer_version_tag_names] = associations[:tags]&.collect(&:name) || consumer_version.associations[:tags]&.collect(&:name)
153
+ end
154
+
155
+ if consumer_version.associations[:branch_versions]
156
+ attributes[:consumer_version_branch_names] = consumer_version.branch_versions.collect(&:branch_name)
157
+ end
158
+
159
+ PactBroker::Domain::Pact.new(attributes)
143
160
  end
161
+ # rubocop:enable Metrics/CyclomaticComplexity
144
162
 
145
163
  def to_domain_lightweight
146
164
  PactBroker::Domain::Pact.new(
@@ -132,10 +132,14 @@ module PactBroker
132
132
  .remove_overridden_revisions_from_complete_query
133
133
  end
134
134
 
135
+ # The pact that belongs to the branch head.
136
+ # May return nil if the branch head does not have a pact published for it.
135
137
  def latest_for_consumer_branch(branch_name)
136
138
  for_branch_heads(branch_name)
137
139
  end
138
140
 
141
+ # The latest pact that belongs to a version on the specified branch (might not be the version that is the branch head)
142
+ # Always returns a pact, if any pacts exist for this branch.
139
143
  def old_latest_for_consumer_branch(branch_name)
140
144
  branch_versions_join = {
141
145
  Sequel[:pact_publications][:consumer_version_id] => Sequel[:branch_versions][:version_id]
@@ -148,7 +152,7 @@ module PactBroker
148
152
 
149
153
  max_orders = join(:branch_versions, branch_versions_join)
150
154
  .join(:branches, branches_join)
151
- .select_group(:consumer_id, :provider_id, Sequel[:branches][:name].as(:branch_name))
155
+ .select_group(Sequel[:pact_publications][:consumer_id], Sequel[:pact_publications][:provider_id], Sequel[:branches][:name].as(:branch_name))
152
156
  .select_append{ max(consumer_version_order).as(latest_consumer_version_order) }
153
157
 
154
158
  max_join = {
@@ -1,5 +1,4 @@
1
- require "sequel"
2
- require "pact_broker/repositories/helpers"
1
+ require "pact_broker/dataset"
3
2
  require "pact_broker/pacts/content"
4
3
  require "pact_broker/pacts/pact_version_association_loaders"
5
4
 
@@ -52,7 +51,7 @@ module PactBroker
52
51
  )
53
52
 
54
53
  dataset_module do
55
- include PactBroker::Repositories::Helpers
54
+ include PactBroker::Dataset
56
55
 
57
56
  def for_pact_domain(pact_domain)
58
57
  where(
@@ -1,9 +1,7 @@
1
- require "sequel"
2
1
  require "pact_broker/logging"
3
2
  require "pact_broker/pacts/pact_publication"
4
3
  require "pact_broker/domain"
5
4
  require "pact_broker/pacts/verifiable_pact"
6
- require "pact_broker/repositories/helpers"
7
5
  require "pact_broker/pacts/selected_pact"
8
6
  require "pact_broker/pacts/selector"
9
7
  require "pact_broker/pacts/selectors"
@@ -17,7 +15,6 @@ module PactBroker
17
15
  include PactBroker::Logging
18
16
  include PactBroker::Repositories
19
17
  include PactBroker::Services
20
- include PactBroker::Repositories::Helpers
21
18
  include PactBroker::Repositories::Scopes
22
19
 
23
20
  PUBLICATION_ASSOCIATIONS_FOR_EAGER_LOAD = [
@@ -221,9 +218,9 @@ module PactBroker
221
218
 
222
219
  def create_selectors_for_wip_pact(pact_publication)
223
220
  if pact_publication.values[:tag_name]
224
- Selectors.create_for_latest_for_tag(pact_publication.values[:tag_name])
221
+ Selectors.create_for_latest_for_tag(pact_publication.values[:tag_name]).resolve(pact_publication.consumer_version)
225
222
  else
226
- Selectors.create_for_latest_for_branch(pact_publication.values.fetch(:branch_name))
223
+ Selectors.create_for_latest_for_branch(pact_publication.values.fetch(:branch_name)).resolve(pact_publication.consumer_version)
227
224
  end
228
225
  end
229
226
 
@@ -6,11 +6,13 @@ module PactBroker
6
6
  def initialize
7
7
  consumer = OpenStruct.new(name: "placeholder-consumer", labels: [OpenStruct.new(name: "placeholder-consumer-label")])
8
8
  @provider = OpenStruct.new(name: "placeholder-provider", labels: [OpenStruct.new(name: "placeholder-provider-label")])
9
- @consumer_version = OpenStruct.new(number: "gggghhhhjjjjkkkkllll66667777888899990000", pacticipant: consumer, tags: [OpenStruct.new(name: "master")])
9
+ @consumer_version = OpenStruct.new(number: "gggghhhhjjjjkkkkllll66667777888899990000", pacticipant: consumer)
10
10
  @consumer_version_number = @consumer_version.number
11
11
  @created_at = DateTime.now
12
12
  @revision_number = 1
13
13
  @pact_version_sha = "5d445a4612743728dfd99ccd4210423c052bb9db"
14
+ @consumer_version_tag_names = ["dev"]
15
+ @consumer_version_branch_names = ["main"]
14
16
  end
15
17
  end
16
18
  end
@@ -1,4 +1,3 @@
1
- require "sequel"
2
1
  require "ostruct"
3
2
  require "pact_broker/logging"
4
3
  require "pact_broker/pacts/generate_sha"
@@ -9,7 +8,6 @@ require "pact_broker/domain"
9
8
  require "pact_broker/pacts/parse"
10
9
  require "pact_broker/pacts/latest_pact_publication_id_for_consumer_version"
11
10
  require "pact_broker/pacts/verifiable_pact"
12
- require "pact_broker/repositories/helpers"
13
11
  require "pact_broker/pacts/selected_pact"
14
12
  require "pact_broker/pacts/selector"
15
13
  require "pact_broker/pacts/selectors"
@@ -24,7 +22,6 @@ module PactBroker
24
22
  class Repository
25
23
  include PactBroker::Logging
26
24
  include PactBroker::Repositories
27
- include PactBroker::Repositories::Helpers
28
25
 
29
26
  def scope_for(scope)
30
27
  PactBroker.policy_scope!(scope)
@@ -53,7 +50,7 @@ module PactBroker
53
50
  consumer_version_order: params.fetch(:version).order,
54
51
  ).upsert
55
52
  update_latest_pact_publication_ids(pact_publication)
56
- pact_publication.to_domain
53
+ pact_publication.with_version_branches_and_tags.to_domain
57
54
  end
58
55
 
59
56
  def update id, params
@@ -75,9 +72,9 @@ module PactBroker
75
72
  created_at: Sequel.datetime_class.now
76
73
  ).upsert
77
74
  update_latest_pact_publication_ids(pact_publication)
78
- pact_publication.to_domain
75
+ pact_publication.with_version_branches_and_tags.to_domain
79
76
  else
80
- existing_model.to_domain
77
+ existing_model.with_version_branches_and_tags.to_domain
81
78
  end
82
79
  end
83
80
 
@@ -201,7 +198,7 @@ module PactBroker
201
198
  .sort
202
199
  end
203
200
 
204
- def find_latest_pact(consumer_name, provider_name, tag = nil)
201
+ def find_latest_pact(consumer_name, provider_name, tag = nil, branch_name = nil)
205
202
  query = scope_for(PactPublication)
206
203
  .eager_for_domain_with_content
207
204
  .select_all_qualified
@@ -212,6 +209,8 @@ module PactBroker
212
209
  query = query.untagged
213
210
  elsif tag
214
211
  query = query.for_consumer_version_tag_all_revisions(tag)
212
+ elsif branch_name
213
+ query = query.old_latest_for_consumer_branch(branch_name)
215
214
  end
216
215
  query.latest_by_consumer_version_order.all.collect(&:to_domain_with_content)[0]
217
216
  end
@@ -253,23 +252,24 @@ module PactBroker
253
252
  .reverse_order(:consumer_version_order, :revision_number)
254
253
  .limit(1)
255
254
 
255
+ # Must use .all to trigger the eager loading
256
256
  if consumer_version_number && !pact_version_sha
257
257
  pact_publication_by_consumer_version
258
- .first&.to_domain_with_content
258
+ .all.first&.to_domain_with_content
259
259
  elsif pact_version_sha && !consumer_version_number
260
260
  latest_pact_publication_by_sha
261
- .first&.to_domain_with_content
261
+ .all.first&.to_domain_with_content
262
262
  elsif consumer_version_number && pact_version_sha
263
- pact_publication = pact_publication_by_consumer_version.first
263
+ pact_publication = pact_publication_by_consumer_version.all.first
264
264
  if pact_publication && pact_publication.pact_version.sha == pact_version_sha
265
265
  pact_publication.to_domain_with_content
266
266
  else
267
- latest_pact_publication_by_sha.first&.to_domain_with_content
267
+ latest_pact_publication_by_sha.all.first&.to_domain_with_content
268
268
  end
269
269
  else
270
270
  pact_publication_by_consumer_version
271
271
  .reverse_order(:consumer_version_order, :revision_number)
272
- .first&.to_domain_with_content
272
+ .all.first&.to_domain_with_content
273
273
  end
274
274
  end
275
275
  # rubocop: enable Metrics/CyclomaticComplexity, Metrics/MethodLength
@@ -22,8 +22,12 @@ module PactBroker
22
22
  extend PactBroker::Messages
23
23
  extend SquashPactsForVerification
24
24
 
25
+ def generate_sha(json_content)
26
+ PactBroker.configuration.sha_generator.call(json_content)
27
+ end
28
+
25
29
  def find_latest_pact params
26
- pact_repository.find_latest_pact(params[:consumer_name], params[:provider_name], params[:tag])
30
+ pact_repository.find_latest_pact(params[:consumer_name], params[:provider_name], params[:tag], params[:branch_name])
27
31
  end
28
32
 
29
33
  def search_for_latest_pact params
@@ -154,10 +158,12 @@ module PactBroker
154
158
  end
155
159
 
156
160
  # Overwriting an existing pact with the same consumer/provider/consumer version number
161
+ # by creating a new revision (that is, a new PactPublication with an incremented revision number)
162
+ # Modifing pacts is strongly discouraged now, and support for it will be dropped in the next major version of the Pact Broker
157
163
  def create_pact_revision params, existing_pact
158
164
  logger.info("Updating existing pact publication", params.without(:json_content))
159
165
  logger.debug("Content #{params[:json_content]}")
160
- pact_version_sha = generate_sha(params[:json_content])
166
+ pact_version_sha = params.fetch(:pact_version_sha)
161
167
  json_content = add_interaction_ids(params[:json_content])
162
168
  update_params = { pact_version_sha: pact_version_sha, json_content: json_content }
163
169
  updated_pact = pact_repository.update(existing_pact.id, update_params)
@@ -178,21 +184,20 @@ module PactBroker
178
184
 
179
185
  private :create_pact_revision
180
186
 
181
- def disallowed_modification?(existing_pact, new_json_content)
182
- !PactBroker.configuration.allow_dangerous_contract_modification && existing_pact && existing_pact.pact_version_sha != generate_sha(new_json_content)
187
+ def disallowed_modification?(existing_pact, new_pact_version_sha)
188
+ !PactBroker.configuration.allow_dangerous_contract_modification && existing_pact && existing_pact.pact_version_sha != new_pact_version_sha
183
189
  end
184
190
 
185
191
  # When no publication for the given consumer/provider/consumer version number exists
186
- def create_pact params, version, provider
192
+ def create_pact(params, version, provider)
187
193
  logger.info("Creating new pact publication", params.without(:json_content))
188
194
  logger.debug("Content #{params[:json_content]}")
189
- pact_version_sha = generate_sha(params[:json_content])
190
195
  json_content = add_interaction_ids(params[:json_content])
191
196
  pact = pact_repository.create(
192
197
  version_id: version.id,
193
198
  provider_id: provider.id,
194
199
  consumer_id: version.pacticipant_id,
195
- pact_version_sha: pact_version_sha,
200
+ pact_version_sha: params.fetch(:pact_version_sha),
196
201
  json_content: json_content,
197
202
  version: version
198
203
  )
@@ -212,12 +217,6 @@ module PactBroker
212
217
 
213
218
  private :create_pact
214
219
 
215
- def generate_sha(json_content)
216
- PactBroker.configuration.sha_generator.call(json_content)
217
- end
218
-
219
- private :generate_sha
220
-
221
220
  def add_interaction_ids(json_content)
222
221
  Content.from_json(json_content).with_ids.to_json
223
222
  end
@@ -47,6 +47,10 @@ module PactBroker
47
47
  get_repository(:matrix_repository)
48
48
  end
49
49
 
50
+ def branch_repository
51
+ get_repository(:branch_repository)
52
+ end
53
+
50
54
  def branch_version_repository
51
55
  get_repository(:branch_version_repository)
52
56
  end
@@ -96,6 +100,11 @@ module PactBroker
96
100
  Matrix::Repository.new
97
101
  end
98
102
 
103
+ register_repository(:branch_repository) do
104
+ require "pact_broker/versions/branch_repository"
105
+ PactBroker::Versions::BranchRepository.new
106
+ end
107
+
99
108
  register_repository(:branch_version_repository) do
100
109
  require "pact_broker/versions/branch_version_repository"
101
110
  PactBroker::Versions::BranchVersionRepository.new
@@ -105,7 +114,6 @@ module PactBroker
105
114
  require "pact_broker/integrations/repository"
106
115
  PactBroker::Integrations::Repository.new
107
116
  end
108
-
109
117
  # rubocop: enable Metrics/MethodLength
110
118
  end
111
119
  end
@@ -37,6 +37,10 @@ module PactBroker
37
37
  end
38
38
 
39
39
  refine String do
40
+ def integer?
41
+ self =~ /^\d+$/
42
+ end
43
+
40
44
  def present?
41
45
  !blank?
42
46
  end
@@ -1,12 +1,9 @@
1
- require "pact_broker/db"
2
- require "pact_broker/repositories/helpers"
1
+ require "pact_broker/dataset"
3
2
 
4
3
  module PactBroker
5
4
  module Tags
6
5
  class HeadPactTag < Sequel::Model
7
- dataset_module do
8
- include PactBroker::Repositories::Helpers
9
- end
6
+ dataset_module(PactBroker::Dataset)
10
7
  end
11
8
  end
12
9
  end
@@ -1,12 +1,8 @@
1
1
  require "pact_broker/domain/tag"
2
- require "pact_broker/repositories/helpers"
3
2
 
4
3
  module PactBroker
5
4
  module Tags
6
5
  class Repository
7
-
8
- include PactBroker::Repositories::Helpers
9
-
10
6
  def create args
11
7
  params = {
12
8
  name: args.fetch(:name),
@@ -22,9 +18,9 @@ module PactBroker
22
18
  .select_all_qualified
23
19
  .join(:versions, { id: :version_id })
24
20
  .join(:pacticipants, {Sequel.qualify("pacticipants", "id") => Sequel.qualify("versions", "pacticipant_id")})
25
- .where(name_like(Sequel.qualify("tags", "name"), args.fetch(:tag_name)))
26
- .where(name_like(Sequel.qualify("versions", "number"), args.fetch(:pacticipant_version_number)))
27
- .where(name_like(Sequel.qualify("pacticipants", "name"), args.fetch(:pacticipant_name)))
21
+ .where(Sequel.name_like(Sequel.qualify("tags", "name"), args.fetch(:tag_name)))
22
+ .where(Sequel.name_like(Sequel.qualify("versions", "number"), args.fetch(:pacticipant_version_number)))
23
+ .where(Sequel.name_like(Sequel.qualify("pacticipants", "name"), args.fetch(:pacticipant_name)))
28
24
  .single_record
29
25
  end
30
26
 
@@ -31,6 +31,8 @@ require "pact_broker/deployments/released_version_service"
31
31
  require "pact_broker/versions/branch_version_repository"
32
32
  require "pact_broker/integrations/repository"
33
33
  require "pact_broker/contracts/service"
34
+ require "pact_broker/contracts/contract_to_publish"
35
+ require "pact_broker/contracts/contracts_to_publish"
34
36
 
35
37
  require "ostruct"
36
38
 
@@ -86,6 +88,12 @@ module PactBroker
86
88
  self
87
89
  end
88
90
 
91
+ # Creates a consumer, consumer version, provider and pact with the specified JSON content
92
+ # Does NOT rely on previous state.
93
+ # @param [String] consumer_name
94
+ # @param [String] consumer_version_number
95
+ # @param [Strig] provider_name
96
+ # @param [String] json_content
89
97
  def create_pact_with_hierarchy consumer_name = "Consumer", consumer_version_number = "1.2.3", provider_name = "Provider", json_content = nil
90
98
  use_consumer(consumer_name)
91
99
  create_consumer(consumer_name) if !consumer
@@ -97,18 +105,39 @@ module PactBroker
97
105
  self
98
106
  end
99
107
 
108
+ # Creates a consumer, consumer version with tag, provider and pact
109
+ # Does NOT rely on previous state.
110
+ # @param [String] consumer_name
111
+ # @param [String] consumer_version_number
112
+ # @param [String] consumer_version_tag_name
113
+ # @param [Strig] provider_name
100
114
  def create_pact_with_consumer_version_tag consumer_name, consumer_version_number, consumer_version_tag_name, provider_name
101
115
  create_pact_with_hierarchy(consumer_name, consumer_version_number, provider_name)
102
116
  create_consumer_version_tag(consumer_version_tag_name)
103
117
  self
104
118
  end
105
119
 
120
+ # Creates a consumer, consumer version, provider, pact and verification
121
+ # Does NOT rely on previous state.
122
+ # @param [String] consumer_name
123
+ # @param [String] consumer_version
124
+ # @param [String] provider_name
125
+ # @param [String] provider_version
126
+ # @param [Boolean] success default true
106
127
  def create_pact_with_verification consumer_name = "Consumer", consumer_version = "1.0.#{model_counter}", provider_name = "Provider", provider_version = "1.0.#{model_counter}", success = true
107
128
  create_pact_with_hierarchy(consumer_name, consumer_version, provider_name)
108
129
  create_verification(number: model_counter, provider_version: provider_version, success: success)
109
130
  self
110
131
  end
111
132
 
133
+ # Creates a consumer, consumer version, provider, pact and verification
134
+ # Does NOT rely on previous state.
135
+ # @param [String] consumer_name
136
+ # @param [String] consumer_version
137
+ # @param [Array<String>] consumer_version_tags
138
+ # @param [String] provider_name
139
+ # @param [String] provider_version
140
+ # @param [Array<String>] provider_version_tags
112
141
  def create_pact_with_verification_and_tags consumer_name = "Consumer", consumer_version = "1.0.#{model_counter}", consumer_version_tags = [], provider_name = "Provider", provider_version = "1.0.#{model_counter}", provider_version_tags = []
113
142
  create_pact_with_hierarchy(consumer_name, consumer_version, provider_name)
114
143
  consumer_version_tags.each do | tag |
@@ -118,6 +147,10 @@ module PactBroker
118
147
  self
119
148
  end
120
149
 
150
+ # Create a pacticipant and version
151
+ # Does NOT rely on previous state
152
+ # @param [String] pacticipant_name
153
+ # @param [String] pacticipant_version
121
154
  def create_version_with_hierarchy pacticipant_name, pacticipant_version
122
155
  pacticipant = pacticipant_service.create(:name => pacticipant_name)
123
156
  version = PactBroker::Domain::Version.create(:number => pacticipant_version, :pacticipant => pacticipant)
@@ -223,7 +256,13 @@ module PactBroker
223
256
  def publish_pact(consumer_name:, provider_name:, consumer_version_number: , tags: nil, branch: nil, build_url: nil, json_content: nil)
224
257
  json_content = json_content || random_json_content(consumer_name, provider_name)
225
258
  contracts = [
226
- PactBroker::Contracts::ContractToPublish.from_hash(consumer_name: consumer_name, provider_name: provider_name, decoded_content: json_content, content_type: "application/json", specification: "pact")
259
+ PactBroker::Contracts::ContractToPublish.from_hash(
260
+ consumer_name: consumer_name,
261
+ provider_name: provider_name,
262
+ decoded_content: json_content,
263
+ content_type: "application/json",
264
+ specification: "pact",
265
+ pact_version_sha: PactBroker::Pacts::GenerateSha.call(json_content))
227
266
  ]
228
267
  contracts_to_publish = PactBroker::Contracts::ContractsToPublish.from_hash(
229
268
  pacticipant_name: consumer_name,
@@ -386,6 +425,14 @@ module PactBroker
386
425
  self
387
426
  end
388
427
 
428
+ # @param [Hash] parameters
429
+ # @option parameters [String] :provider_version
430
+ # @option parameters [Array<String>] :tag_names
431
+ # @option parameters [String] :branch
432
+ # @option parameters [Boolean] :success
433
+ # @option parameters [Integer] :number
434
+ # @option parameters [Boolean] :wip
435
+ # @option parameters [Boolean] :test_results
389
436
  def create_verification parameters = {}
390
437
  # This should use the verification service. what a mess
391
438
  parameters.delete(:comment)
@@ -493,6 +540,10 @@ module PactBroker
493
540
  instance_variable_get("@#{instance_variable_name}")
494
541
  end
495
542
 
543
+ def clear_now
544
+ @now = nil
545
+ end
546
+
496
547
  def set_now date
497
548
  @now = date.to_date
498
549
  self
@@ -602,6 +653,10 @@ module PactBroker
602
653
  tag = PactBroker::Domain::Tag.create(name: tag_name, version: version)
603
654
  set_created_at_if_set(params[:created_at], :tags, { name: tag.name, version_id: version.id })
604
655
  end
656
+ if params[:branch]
657
+ set_created_at_if_set params[:created_at], :branches, { name: params[:branch], pacticipant_id: pacticipant.id }
658
+ set_created_at_if_set params[:created_at], :branch_versions, { branch_name: params[:branch], pacticipant_id: pacticipant.id, version_id: version.id }
659
+ end
605
660
  version
606
661
  end
607
662
 
@@ -638,7 +693,7 @@ module PactBroker
638
693
  if date_to_set
639
694
  Sequel::Model.db[table_name].where(selector).update(date_column_name => date_to_set)
640
695
  if Sequel::Model.db.schema(table_name).any?{ |col| col.first == :updated_at }
641
- Sequel::Model.db[table_name].where(selector.keys.first => selector.values.first).update(updated_at: date_to_set)
696
+ Sequel::Model.db[table_name].where(selector).update(updated_at: date_to_set)
642
697
  end
643
698
  end
644
699
  end
@@ -10,8 +10,10 @@ module PactBroker
10
10
  using PactBroker::StringRefinements
11
11
 
12
12
  set :root, File.join(File.dirname(__FILE__), "..")
13
- set :show_exceptions, ENV["RACK_ENV"] != "production"
14
- set :dump_errors, false # The padrino logger logs these for us. If this is enabled we get duplicate logging.
13
+ set :show_exceptions, ENV["RACK_ENV"] == "development"
14
+ # The padrino logger logs these for us, but only in production. If this is enabled we get duplicate logging.
15
+ set :dump_errors, ENV["RACK_ENV"] != "production"
16
+ set :raise_errors, ENV["RACK_ENV"] == "test"
15
17
 
16
18
  def base_url
17
19
  # Using the X-Forwarded headers in the UI can leave the app vulnerable
@@ -30,12 +30,13 @@ module PactBroker
30
30
  pacticipant = pacticipant_service.find_pacticipant_by_name(params[:name])
31
31
  {
32
32
  csv_path: "#{base_url}/groups/#{ERB::Util.url_encode(params[:name])}.csv",
33
+ max_pacticipants: PactBroker.configuration.network_diagram_max_pacticipants,
33
34
  pacticipant_name: params[:name],
34
35
  repository_url: pacticipant&.repository_url,
35
36
  base_url: base_url,
36
37
  pacticipant: pacticipant,
37
38
  details_url: "#{base_url}/pacticipants/#{ERB::Util.url_encode(params[:name])}",
38
- network_url: "#{base_url}/pacticipants/#{ERB::Util.url_encode(params[:name])}/network"
39
+ network_url: "#{base_url}/pacticipants/#{ERB::Util.url_encode(params[:name])}/network?maxPacticipants=#{PactBroker.configuration.network_diagram_max_pacticipants}"
39
40
  }.merge(overrides)
40
41
  end
41
42
  end
@@ -110,14 +110,14 @@ module PactBroker
110
110
 
111
111
  def latest_consumer_version_tags
112
112
  @line.consumer_version_tags
113
- .select(&:latest)
113
+ .select(&:latest?)
114
114
  .sort_by(&:created_at)
115
115
  .collect{ | tag | MatrixTag.new(tag.to_hash.merge(pacticipant_name: consumer_name, version_number: consumer_version_number)) }
116
116
  end
117
117
 
118
118
  def other_consumer_version_tags
119
119
  @line.consumer_version_tags
120
- .reject(&:latest)
120
+ .reject(&:latest?)
121
121
  .sort_by(&:created_at)
122
122
  .collect{ | tag | MatrixTag.new(tag.to_hash.merge(pacticipant_name: consumer_name, version_number: consumer_version_number)) }
123
123
  end
@@ -138,14 +138,14 @@ module PactBroker
138
138
 
139
139
  def latest_provider_version_tags
140
140
  @line.provider_version_tags
141
- .select(&:latest)
141
+ .select(&:latest?)
142
142
  .sort_by(&:created_at)
143
143
  .collect{ | tag | MatrixTag.new(tag.to_hash.merge(pacticipant_name: provider_name, version_number: provider_version_number)) }
144
144
  end
145
145
 
146
146
  def other_provider_version_tags
147
147
  @line.provider_version_tags
148
- .reject(&:latest)
148
+ .reject(&:latest?)
149
149
  .sort_by(&:created_at)
150
150
  .collect{ | tag | MatrixTag.new(tag.to_hash.merge(pacticipant_name: provider_name, version_number: provider_version_number)) }
151
151
  end
@@ -329,8 +329,9 @@ window.onload = function() {
329
329
  .attr("d","M 10 0 L 10 10 L 0 5 z")
330
330
  .attr("fill", "#A0A0A0");
331
331
 
332
+ const maxPacticipants = new URL(location).searchParams.get("maxPacticipants") || <%= max_pacticipants %>;
332
333
 
333
- d3.text("<%= csv_path %>", "text/csv", function(unparsedData) {
334
+ d3.text(`<%= csv_path %>?maxPacticipants=${maxPacticipants}`, "text/csv", function(unparsedData) {
334
335
  var data=d3.csv.parseRows(unparsedData);
335
336
  pacticipants = parseCSV(data);
336
337
  pacticipantNameArray = getPacticipantNames(pacticipants);
@@ -1,14 +1,25 @@
1
- require "pact_broker/configuration"
1
+ # Must be defined before loading Padrino
2
2
  # Stop Padrino creating a log file, as it will try to create it in the gems directory
3
3
  # http://www.padrinorb.com/api/Padrino/Logger.html
4
- unless defined? PADRINO_LOGGER
5
- log_path = File.join(PactBroker.configuration.log_dir, "ui.log")
6
- PADRINO_LOGGER = {
7
- production: { log_level: :error, stream: :to_file, log_path: log_path },
8
- staging: { log_level: :error, stream: :to_file, log_path: log_path },
9
- test: { log_level: :warn, stream: :to_file, log_path: log_path },
10
- development: { log_level: :warn, stream: :to_file, log_path: log_path }
11
- }
4
+ # This configuration will be replaced by the SemanticLogger later on.
5
+ PADRINO_LOGGER ||= {
6
+ ENV.fetch("RACK_ENV", "production").to_sym => { stream: :stdout }
7
+ }
8
+
9
+ require "padrino-core"
10
+
11
+ class PactBrokerPadrinoLogger < SemanticLogger::Logger
12
+ include Padrino::Logger::Extensions
13
+
14
+ # Padrino expects level to return an integer, not a symbol
15
+ def level
16
+ Padrino::Logger::Levels[SemanticLogger.default_level]
17
+ end
12
18
  end
13
19
 
20
+ Padrino.logger = PactBrokerPadrinoLogger.new("Padrino")
21
+ # Log a test message to ensure that the logger works properly, as it only
22
+ # seems to be used in production.
23
+ Padrino.logger.info("Padrino has been configured with SemanticLogger")
24
+
14
25
  require "pact_broker/ui/app"
@@ -2,9 +2,6 @@ require "pact_broker/domain/verification"
2
2
 
3
3
  module PactBroker
4
4
  module Verifications
5
-
6
- include PactBroker::Repositories::Helpers
7
-
8
5
  class LatestVerificationForConsumerAndProvider < PactBroker::Domain::Verification
9
6
  set_dataset(:latest_verifications_for_consumer_and_provider)
10
7