pact_broker 2.75.0 → 2.78.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (193) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +12 -0
  3. data/.github/workflows/test-ruby-3.yml +19 -0
  4. data/.github/workflows/test.yml +19 -4
  5. data/.gitignore +3 -1
  6. data/CHANGELOG.md +48 -0
  7. data/DEVELOPER_SETUP.md +62 -3
  8. data/Dockerfile +1 -0
  9. data/ISSUES.md +13 -5
  10. data/README.md +1 -1
  11. data/config.ru +1 -0
  12. data/db/ddl_statements/head_pact_tags.rb +24 -1
  13. data/db/ddl_statements/latest_tagged_pact_consumer_version_orders.rb +11 -0
  14. data/db/ddl_statements/latest_tagged_pact_publications.rb +6 -0
  15. data/db/ddl_statements/latest_verification_ids_for_consumer_version_tags.rb +13 -0
  16. data/db/migrations/20210117_add_branch_to_version.rb +9 -0
  17. data/db/migrations/20210202_add_created_at_to_head_pact_tags.rb +14 -0
  18. data/db/migrations/20210205_add_pacticipant_id_to_tag.rb +17 -0
  19. data/db/migrations/20210206_add_index_to_tags_and_versions.rb +27 -0
  20. data/db/migrations/20210207_optimise_latest_verification_ids_for_consumer_version_tags.rb +13 -0
  21. data/db/migrations/20210208_optimise_latest_tagged_pact_cv_orders.rb +13 -0
  22. data/db/migrations/20210210_create_environments_table.rb +16 -0
  23. data/docker-compose-issue-repro-with-pact-broker-docker-image.yml +44 -0
  24. data/lib/pact_broker/api.rb +7 -2
  25. data/lib/pact_broker/api/contracts/dry_validation_predicates.rb +8 -0
  26. data/lib/pact_broker/api/contracts/environment_schema.rb +49 -0
  27. data/lib/pact_broker/api/decorators/base_decorator.rb +11 -0
  28. data/lib/pact_broker/api/decorators/dashboard_decorator.rb +5 -1
  29. data/lib/pact_broker/api/decorators/environment_decorator.rb +30 -0
  30. data/lib/pact_broker/api/decorators/environments_decorator.rb +21 -0
  31. data/lib/pact_broker/api/decorators/matrix_decorator.rb +8 -2
  32. data/lib/pact_broker/api/decorators/reason_decorator.rb +2 -2
  33. data/lib/pact_broker/api/decorators/verifiable_pacts_query_decorator.rb +2 -0
  34. data/lib/pact_broker/api/decorators/version_decorator.rb +15 -2
  35. data/lib/pact_broker/api/pact_broker_urls.rb +8 -0
  36. data/lib/pact_broker/api/paths.rb +5 -0
  37. data/lib/pact_broker/api/resources/default_base_resource.rb +15 -2
  38. data/lib/pact_broker/api/resources/environment.rb +76 -0
  39. data/lib/pact_broker/api/resources/environments.rb +75 -0
  40. data/lib/pact_broker/api/resources/index.rb +20 -0
  41. data/lib/pact_broker/api/resources/latest_version.rb +27 -0
  42. data/lib/pact_broker/api/resources/provider_pacts_for_verification.rb +1 -0
  43. data/lib/pact_broker/api/resources/verifications.rb +5 -2
  44. data/lib/pact_broker/api/resources/version.rb +15 -9
  45. data/lib/pact_broker/api/resources/webhook_execution.rb +1 -1
  46. data/lib/pact_broker/app.rb +3 -0
  47. data/lib/pact_broker/certificates/certificate.rb +1 -1
  48. data/lib/pact_broker/config/setting.rb +1 -1
  49. data/lib/pact_broker/config/space_delimited_integer_list.rb +25 -0
  50. data/lib/pact_broker/configuration.rb +18 -1
  51. data/lib/pact_broker/db/data_migrations/helpers.rb +4 -0
  52. data/lib/pact_broker/db/data_migrations/set_extra_columns_for_tags.rb +29 -0
  53. data/lib/pact_broker/db/migrate_data.rb +1 -0
  54. data/lib/pact_broker/db/seed_example_data.rb +13 -13
  55. data/lib/pact_broker/deployments/environment.rb +15 -0
  56. data/lib/pact_broker/deployments/environment_service.rb +39 -0
  57. data/lib/pact_broker/doc/controllers/app.rb +1 -1
  58. data/lib/pact_broker/doc/views/index/environment.markdown +37 -0
  59. data/lib/pact_broker/doc/views/index/environments.markdown +53 -0
  60. data/lib/pact_broker/doc/views/index/latest-pact-versions.markdown +1 -1
  61. data/lib/pact_broker/doc/views/index/pacticipant-version-tag.markdown +1 -0
  62. data/lib/pact_broker/doc/views/index/pacticipant-version.markdown +13 -0
  63. data/lib/pact_broker/domain/index_item.rb +18 -4
  64. data/lib/pact_broker/domain/pacticipant.rb +9 -5
  65. data/lib/pact_broker/domain/tag.rb +131 -71
  66. data/lib/pact_broker/domain/verification.rb +3 -2
  67. data/lib/pact_broker/domain/version.rb +58 -23
  68. data/lib/pact_broker/domain/webhook.rb +12 -9
  69. data/lib/pact_broker/hash_refinements.rb +4 -0
  70. data/lib/pact_broker/index/service.rb +55 -49
  71. data/lib/pact_broker/locale/en.yml +3 -1
  72. data/lib/pact_broker/matrix/quick_row.rb +8 -0
  73. data/lib/pact_broker/metrics/service.rb +1 -1
  74. data/lib/pact_broker/pacts/eager_loaders.rb +52 -0
  75. data/lib/pact_broker/pacts/latest_pact_publication_id_for_consumer_version.rb +18 -13
  76. data/lib/pact_broker/pacts/lazy_loaders.rb +14 -0
  77. data/lib/pact_broker/pacts/pact_publication.rb +38 -84
  78. data/lib/pact_broker/pacts/pact_publication_dataset_module.rb +297 -0
  79. data/lib/pact_broker/pacts/pact_version.rb +1 -2
  80. data/lib/pact_broker/pacts/pacts_for_verification_repository.rb +286 -0
  81. data/lib/pact_broker/pacts/repository.rb +5 -231
  82. data/lib/pact_broker/pacts/selected_pact.rb +4 -0
  83. data/lib/pact_broker/pacts/selector.rb +56 -1
  84. data/lib/pact_broker/pacts/selectors.rb +16 -0
  85. data/lib/pact_broker/pacts/service.rb +6 -8
  86. data/lib/pact_broker/pacts/squash_pacts_for_verification.rb +1 -4
  87. data/lib/pact_broker/pacts/verifiable_pact.rb +45 -2
  88. data/lib/pact_broker/pacts/verifiable_pact_messages.rb +56 -16
  89. data/lib/pact_broker/repositories/helpers.rb +4 -0
  90. data/lib/pact_broker/services.rb +9 -0
  91. data/lib/pact_broker/tags/eager_loaders.rb +47 -0
  92. data/lib/pact_broker/tags/repository.rb +3 -1
  93. data/lib/pact_broker/tags/service.rb +0 -3
  94. data/lib/pact_broker/tags/tag_with_latest_flag.rb +1 -0
  95. data/lib/pact_broker/test/http_test_data_builder.rb +101 -35
  96. data/lib/pact_broker/test/test_data_builder.rb +50 -3
  97. data/lib/pact_broker/ui/app.rb +6 -0
  98. data/lib/pact_broker/ui/controllers/base_controller.rb +5 -1
  99. data/lib/pact_broker/ui/controllers/pacts.rb +18 -0
  100. data/lib/pact_broker/ui/view_models/index_item.rb +9 -0
  101. data/lib/pact_broker/ui/view_models/matrix_line.rb +36 -0
  102. data/lib/pact_broker/ui/views/index/show-with-tags.haml +8 -0
  103. data/lib/pact_broker/ui/views/matrix/show.haml +10 -0
  104. data/lib/pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version.rb +7 -5
  105. data/lib/pact_broker/verifications/service.rb +2 -1
  106. data/lib/pact_broker/version.rb +1 -1
  107. data/lib/pact_broker/versions/eager_loaders.rb +71 -0
  108. data/lib/pact_broker/versions/lazy_loaders.rb +13 -0
  109. data/lib/pact_broker/versions/repository.rb +22 -2
  110. data/lib/pact_broker/versions/service.rb +5 -1
  111. data/lib/pact_broker/webhooks/execution.rb +3 -2
  112. data/lib/pact_broker/webhooks/latest_triggered_webhook.rb +2 -0
  113. data/lib/pact_broker/webhooks/pact_and_verification_parameters.rb +10 -3
  114. data/lib/pact_broker/webhooks/service.rb +8 -7
  115. data/lib/pact_broker/webhooks/trigger_service.rb +56 -23
  116. data/lib/pact_broker/webhooks/triggered_webhook.rb +14 -5
  117. data/lib/pact_broker/webhooks/webhook.rb +1 -1
  118. data/lib/pact_broker/webhooks/webhook_event.rb +1 -1
  119. data/lib/pact_broker/webhooks/webhook_execution_result.rb +4 -1
  120. data/lib/pact_broker/webhooks/webhook_request_logger.rb +5 -1
  121. data/lib/rack/pact_broker/set_base_url.rb +22 -0
  122. data/lib/sequel/plugins/upsert.rb +18 -4
  123. data/public/stylesheets/index.css +22 -1
  124. data/public/stylesheets/matrix.css +0 -21
  125. data/regression/can_i_deploy_spec.rb +5 -4
  126. data/regression/index_spec.rb +26 -0
  127. data/regression/regression_helper.rb +29 -3
  128. data/regression/script/clear.sh +3 -0
  129. data/regression/script/run.sh +3 -0
  130. data/script/demonstrate-version-branches.rb +33 -0
  131. data/script/pry.rb +2 -2
  132. data/script/reproduce-issue-starting-up.rb +13 -23
  133. data/script/reproduce-issue.rb +18 -14
  134. data/script/trigger-release.sh +1 -1
  135. data/script/webhook-server.ru +5 -5
  136. data/spec/features/create_environment_spec.rb +47 -0
  137. data/spec/features/create_tag_spec.rb +32 -0
  138. data/spec/features/create_version_spec.rb +70 -0
  139. data/spec/features/delete_environment_spec.rb +16 -0
  140. data/spec/features/end_deployment_spec.rb +29 -0
  141. data/spec/features/get_environment_spec.rb +19 -0
  142. data/spec/features/get_environments_spec.rb +20 -0
  143. data/spec/features/record_deployment_spec.rb +28 -0
  144. data/spec/features/update_environment_spec.rb +44 -0
  145. data/spec/fixtures/approvals/modifiable_resources.approved.json +6 -0
  146. data/spec/fixtures/dashboard.json +4 -2
  147. data/spec/integration/ui/index_spec.rb +4 -4
  148. data/spec/lib/pact_broker/api/contracts/environment_schema_spec.rb +83 -0
  149. data/spec/lib/pact_broker/api/decorators/dashboard_decorator_spec.rb +4 -2
  150. data/spec/lib/pact_broker/api/decorators/matrix_decorator_spec.rb +11 -6
  151. data/spec/lib/pact_broker/api/decorators/reason_decorator_spec.rb +6 -6
  152. data/spec/lib/pact_broker/api/decorators/verifiable_pacts_query_decorator_spec.rb +6 -0
  153. data/spec/lib/pact_broker/api/decorators/version_decorator_spec.rb +18 -0
  154. data/spec/lib/pact_broker/api/resources/default_base_resource_approval_spec.rb +1 -1
  155. data/spec/lib/pact_broker/api/resources/default_base_resource_spec.rb +1 -12
  156. data/spec/lib/pact_broker/api/resources/provider_pacts_for_verification_spec.rb +4 -0
  157. data/spec/lib/pact_broker/api/resources/verifications_spec.rb +2 -5
  158. data/spec/lib/pact_broker/api/resources/webhook_execution_result_spec.rb +56 -0
  159. data/spec/lib/pact_broker/api/resources/webhook_execution_spec.rb +3 -2
  160. data/spec/lib/pact_broker/config/space_delimited_integer_list_spec.rb +47 -0
  161. data/spec/lib/pact_broker/configuration_spec.rb +12 -0
  162. data/spec/lib/pact_broker/doc/controllers/app_spec.rb +3 -5
  163. data/spec/lib/pact_broker/domain/tag_spec.rb +101 -27
  164. data/spec/lib/pact_broker/domain/version_spec.rb +103 -15
  165. data/spec/lib/pact_broker/domain/webhook_spec.rb +7 -7
  166. data/spec/lib/pact_broker/index/service_spec.rb +89 -15
  167. data/spec/lib/pact_broker/pacts/pact_publication_dataset_module_spec.rb +400 -0
  168. data/spec/lib/pact_broker/pacts/pact_publication_spec.rb +434 -14
  169. data/spec/lib/pact_broker/pacts/repository_find_for_verification_fallback_spec.rb +1 -1
  170. data/spec/lib/pact_broker/pacts/repository_find_for_verification_spec.rb +1 -1
  171. data/spec/lib/pact_broker/pacts/repository_find_wip_pact_versions_for_provider_branch_spec.rb +224 -0
  172. data/spec/lib/pact_broker/pacts/repository_find_wip_pact_versions_for_provider_spec.rb +46 -7
  173. data/spec/lib/pact_broker/pacts/selector_spec.rb +3 -2
  174. data/spec/lib/pact_broker/pacts/service_find_for_verification_spec.rb +2 -3
  175. data/spec/lib/pact_broker/pacts/service_spec.rb +9 -7
  176. data/spec/lib/pact_broker/pacts/verifiable_pact_messages_spec.rb +57 -10
  177. data/spec/lib/pact_broker/tags/repository_spec.rb +2 -0
  178. data/spec/lib/pact_broker/verifications/service_spec.rb +4 -1
  179. data/spec/lib/pact_broker/versions/repository_spec.rb +54 -0
  180. data/spec/lib/pact_broker/webhooks/render_spec.rb +6 -5
  181. data/spec/lib/pact_broker/webhooks/service_spec.rb +13 -9
  182. data/spec/lib/pact_broker/webhooks/trigger_service_spec.rb +60 -18
  183. data/spec/lib/pact_broker/webhooks/webhook_request_logger_spec.rb +8 -0
  184. data/spec/lib/sequel/plugins/upsert_spec.rb +31 -3
  185. data/spec/service_consumers/hal_relation_proxy_app.rb +3 -1
  186. data/spec/service_consumers/provider_states_for_pact_broker_client.rb +16 -0
  187. data/spec/spec_helper.rb +17 -5
  188. data/spec/support/approvals.rb +24 -0
  189. data/spec/support/shared_examples_for_responses.rb +11 -0
  190. data/tasks/db.rake +1 -0
  191. data/tasks/rspec.rake +1 -1
  192. metadata +69 -4
  193. data/docker-compose-issue-repro.yml +0 -22
@@ -16,7 +16,7 @@ module PactBroker
16
16
  associate(:many_to_one, :provider_version, class: "PactBroker::Domain::Version", key: :provider_version_id, primary_key: :id)
17
17
  associate(:many_to_one, :provider, class: "PactBroker::Domain::Pacticipant", key: :provider_id, primary_key: :id)
18
18
  associate(:many_to_one, :consumer, class: "PactBroker::Domain::Pacticipant", key: :consumer_id, primary_key: :id)
19
- associate(:one_to_many, :provider_version_tags, :class => "PactBroker::Tags::TagWithLatestFlag", primary_key: :provider_version_id, key: :version_id)
19
+ associate(:one_to_many, :provider_version_tags, :class => "PactBroker::Domain::Tag", primary_key: :provider_version_id, key: :version_id)
20
20
  plugin :serialization, :json, :test_results
21
21
 
22
22
  def before_create
@@ -197,7 +197,7 @@ end
197
197
 
198
198
  # Table: verifications
199
199
  # Columns:
200
- # id | integer | PRIMARY KEY DEFAULT nextval('verifications_id_seq'::regclass)
200
+ # id | integer | PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
201
201
  # number | integer |
202
202
  # success | boolean | NOT NULL
203
203
  # provider_version | text |
@@ -209,6 +209,7 @@ end
209
209
  # test_results | text |
210
210
  # consumer_id | integer |
211
211
  # provider_id | integer |
212
+ # wip | boolean | NOT NULL DEFAULT false
212
213
  # Indexes:
213
214
  # verifications_pkey | PRIMARY KEY btree (id)
214
215
  # verifications_pact_version_id_number_index | UNIQUE btree (pact_version_id, number)
@@ -2,6 +2,8 @@ require 'pact_broker/db'
2
2
  require 'pact_broker/domain/order_versions'
3
3
  require 'pact_broker/repositories/helpers'
4
4
  require 'pact_broker/tags/tag_with_latest_flag'
5
+ require 'pact_broker/versions/eager_loaders'
6
+ require 'pact_broker/versions/lazy_loaders'
5
7
 
6
8
  module PactBroker
7
9
  module Domain
@@ -22,37 +24,51 @@ module PactBroker
22
24
 
23
25
  class Version < Sequel::Model
24
26
  plugin :timestamps, update_on_create: true
25
- plugin :insert_ignore, identifying_columns: [:pacticipant_id, :number]
27
+ plugin :upsert, { identifying_columns: [:pacticipant_id, :number], ignore_columns_on_update: [:id, :created_at, :order] }
26
28
 
27
29
  set_primary_key :id
28
30
  one_to_many :pact_publications, order: :revision_number, class: "PactBroker::Pacts::PactPublication", key: :consumer_version_id
29
31
  associate(:many_to_one, :pacticipant, :class => "PactBroker::Domain::Pacticipant", :key => :pacticipant_id, :primary_key => :id)
30
32
  one_to_many :tags, :reciprocal => :version, order: :created_at
31
33
 
32
- one_to_many :tags_with_latest_flag, :class => "PactBroker::Tags::TagWithLatestFlag", primary_keys: [:id], key: [:version_id], :eager_loader=>(proc do |eo_opts|
33
- tags_for_versions = PactBroker::Domain::Tag.where(version_id: eo_opts[:key_hash][:id].keys)
34
- latest_tag_for_pacticipants = PactBroker::Domain::Tag.latest_tags_for_pacticipant_ids(eo_opts[:rows].collect(&:pacticipant_id)).all
35
-
36
- eo_opts[:rows].each{|row| row.associations[:tags_with_latest_flag] = [] }
37
-
38
- tags_for_versions.each do | tag |
39
- latest = latest_tag_for_pacticipants.any? { |latest_tag| latest_tag.name == tag.name && latest_tag.version_id == tag.version_id }
40
- eo_opts[:id_map][tag.version_id].each do | version |
41
- version.associations[:tags_with_latest_flag] << EagerTagWithLatestFlag.new(tag, latest)
42
- end
43
- end
44
- end)
34
+ many_to_one :latest_version_for_pacticipant, read_only: true, key: :id,
35
+ class: Version,
36
+ dataset: lambda { Version.latest_version_for_pacticipant(pacticipant) },
37
+ eager_loader: PactBroker::Versions::EagerLoaders::LatestVersionForPacticipant
45
38
 
39
+ many_to_one :latest_version_for_branch, read_only: true, key: :id,
40
+ class: Version,
41
+ dataset: PactBroker::Versions::LazyLoaders::LATEST_VERSION_FOR_BRANCH,
42
+ eager_loader: PactBroker::Versions::EagerLoaders::LatestVersionForBranch
46
43
 
47
44
  dataset_module do
48
45
  include PactBroker::Repositories::Helpers
49
46
 
47
+ def latest_version_for_pacticipant(pacticipant)
48
+ where(pacticipant: pacticipant)
49
+ .order(Sequel.desc(:order))
50
+ .limit(1)
51
+ end
52
+
50
53
  def for(pacticipant_name, version_number)
51
54
  where_pacticipant_name(pacticipant_name).where_number(version_number).single_record
52
55
  end
53
56
 
57
+ def latest_versions_for_pacticipant_branches(pacticipant_id, branches)
58
+ query = Version.where(Sequel[:versions][:pacticipant_id] => pacticipant_id, Sequel[:versions][:branch] => branches)
59
+
60
+ self_join = {
61
+ Sequel[:versions][:pacticipant_id] => Sequel[:versions_2][:pacticipant_id],
62
+ Sequel[:versions][:branch] => Sequel[:versions_2][:branch]
63
+ }
64
+ query.select_all_qualified.left_join(query, self_join, table_alias: :versions_2) do
65
+ Sequel[:versions_2][:order] > Sequel[:versions][:order]
66
+ end
67
+ .where(Sequel[:versions_2][:order] => nil)
68
+ end
69
+
54
70
  def where_pacticipant_name(pacticipant_name)
55
- where(pacticipant_id: db[:pacticipants].select(:id).where(name_like(:name, pacticipant_name)))
71
+ where(Sequel[:versions][:pacticipant_id] => db[:pacticipants].select(:id).where(name_like(:name, pacticipant_name)))
56
72
  # If we do a join, we get the extra columns from the pacticipant table that then
57
73
  # make == not work
58
74
  # join(:pacticipants) do | p |
@@ -118,7 +134,7 @@ module PactBroker
118
134
  Sequel[:versions][:order] => Sequel[:latest][:latest_version_order]
119
135
  }
120
136
 
121
- group_by_cols = selector.tag == true ? [:pacticipant_id, Sequel[:tags][:name]] : [:pacticipant_id]
137
+ group_by_cols = selector.tag == true ? [Sequel[:versions][:pacticipant_id], Sequel[:tags][:name]] : [Sequel[:versions][:pacticipant_id]]
122
138
 
123
139
  max_order_for_each_pacticipant = query
124
140
  .select_group(*group_by_cols)
@@ -128,9 +144,12 @@ module PactBroker
128
144
  end
129
145
  end
130
146
 
147
+ # Isn't called on upsert when the record is updated with Sqlite
148
+ # Is called with Postgres/MySQL
149
+ # Haven't had time to dig into why
131
150
  def after_create
132
151
  super
133
- OrderVersions.(self)
152
+ OrderVersions.(self) unless self.order
134
153
  refresh
135
154
  end
136
155
 
@@ -147,29 +166,45 @@ module PactBroker
147
166
  "Version #{number} - #{updated_at.to_time.localtime.strftime("%d/%m/%Y")}"
148
167
  end
149
168
 
169
+ def head_tags
170
+ tags.select(&:latest_for_pacticipant?)
171
+ end
172
+
150
173
  # What about provider??? This makes no sense
151
174
  def latest_pact_publication
152
175
  pact_publications.last
153
176
  end
177
+
178
+ def latest_for_branch?
179
+ branch ? latest_version_for_branch.order == order : nil
180
+ end
181
+
182
+ def latest_for_pacticipant?
183
+ latest_version_for_pacticipant == self
184
+ end
154
185
  end
155
186
  end
156
187
  end
157
188
 
158
189
  # Table: versions
159
190
  # Columns:
160
- # id | integer | PRIMARY KEY DEFAULT nextval('versions_id_seq'::regclass)
191
+ # id | integer | PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
161
192
  # number | text |
162
193
  # repository_ref | text |
163
194
  # pacticipant_id | integer | NOT NULL
164
195
  # order | integer |
165
196
  # created_at | timestamp without time zone | NOT NULL
166
197
  # updated_at | timestamp without time zone | NOT NULL
198
+ # branch | text |
199
+ # build_url | text |
167
200
  # Indexes:
168
- # versions_pkey | PRIMARY KEY btree (id)
169
- # uq_ver_ppt_ord | UNIQUE btree (pacticipant_id, "order")
170
- # versions_pacticipant_id_number_index | UNIQUE btree (pacticipant_id, number)
171
- # ndx_ver_num | btree (number)
172
- # ndx_ver_ord | btree ("order")
201
+ # versions_pkey | PRIMARY KEY btree (id)
202
+ # uq_ver_ppt_ord | UNIQUE btree (pacticipant_id, "order")
203
+ # versions_pacticipant_id_number_index | UNIQUE btree (pacticipant_id, number)
204
+ # ndx_ver_num | btree (number)
205
+ # ndx_ver_ord | btree ("order")
206
+ # versions_pacticipant_id_branch_order_index | btree (pacticipant_id, branch, "order")
207
+ # versions_pacticipant_id_order_desc_index | btree (pacticipant_id, "order" DESC)
173
208
  # Foreign key constraints:
174
209
  # versions_pacticipant_id_fkey | (pacticipant_id) REFERENCES pacticipants(id)
175
210
  # Referenced By:
@@ -52,15 +52,18 @@ module PactBroker
52
52
  request && request.description
53
53
  end
54
54
 
55
- def execute pact, verification, options
56
- logger.info "Executing #{self} webhook_context=#{options.fetch(:webhook_context)}"
57
- webhook_request = request.build(template_parameters(pact, verification, options))
55
+ def execute pact, verification, event_context, options
56
+ logger.info "Executing #{self} event_context=#{event_context}"
57
+ template_params = template_parameters(pact, verification, event_context, options)
58
+ webhook_request = request.build(template_params)
58
59
  http_response, error = execute_request(webhook_request)
59
60
 
61
+ logs = generate_logs(webhook_request, http_response, error, event_context, options.fetch(:logging_options))
62
+ http_request = webhook_request.http_request
60
63
  PactBroker::Webhooks::WebhookExecutionResult.new(
61
- webhook_request.http_request,
64
+ http_request,
62
65
  http_response,
63
- generate_logs(webhook_request, http_response, error, options[:webhook_context], options.fetch(:logging_options)),
66
+ logs,
64
67
  error
65
68
  )
66
69
  end
@@ -106,18 +109,18 @@ module PactBroker
106
109
  return http_response, error
107
110
  end
108
111
 
109
- def template_parameters(pact, verification, options)
110
- PactBroker::Webhooks::PactAndVerificationParameters.new(pact, verification, options.fetch(:webhook_context)).to_hash
112
+ def template_parameters(pact, verification, event_context, options)
113
+ PactBroker::Webhooks::PactAndVerificationParameters.new(pact, verification, event_context).to_hash
111
114
  end
112
115
 
113
- def generate_logs(webhook_request, http_response, error, webhook_context, logging_options)
116
+ def generate_logs(webhook_request, http_response, error, event_context, logging_options)
114
117
  webhook_request_logger = PactBroker::Webhooks::WebhookRequestLogger.new(logging_options)
115
118
  webhook_request_logger.log(
116
119
  uuid,
117
120
  webhook_request,
118
121
  http_response,
119
122
  error,
120
- webhook_context
123
+ event_context
121
124
  )
122
125
  end
123
126
  end
@@ -30,6 +30,10 @@ module PactBroker
30
30
  keys.each_with_object(Hash.new) { |k, hash| hash[k] = self[k] if has_key?(k) }
31
31
  end
32
32
 
33
+ def without(*keys)
34
+ reject { |k,_| keys.include?(k) }
35
+ end
36
+
33
37
  def camelcase_keys
34
38
  camelcase_keys_private(self)
35
39
  end
@@ -13,14 +13,6 @@ module PactBroker
13
13
  extend PactBroker::Services
14
14
  extend PactBroker::Logging
15
15
 
16
- COLS = [:id, :consumer_name, :provider_name, :consumer_version_order]
17
- LATEST_PPS = Sequel::Model.db[:latest_pact_publications].select(*COLS)
18
- LATEST_TAGGED_PPS = Sequel::Model.db[:latest_tagged_pact_publications].select(*COLS)
19
- HEAD_PP_ORDER_COLUMNS = [
20
- Sequel.asc(Sequel.function(:lower, :consumer_name)),
21
- Sequel.desc(:consumer_version_order),
22
- Sequel.asc(Sequel.function(:lower, :provider_name))
23
- ].freeze
24
16
  DEFAULT_PAGE_SIZE = 30
25
17
  DEFAULT_PAGE_NUMBER = 1
26
18
 
@@ -40,27 +32,26 @@ module PactBroker
40
32
 
41
33
  def self.find_index_items options = {}
42
34
  latest_verifications_for_cv_tags = latest_verifications_for_consumer_version_tags(options)
43
- latest_pact_publication_ids = latest_pact_publications.select(:id).all.collect{ |h| h[:id] }
35
+ latest_pp_ids = latest_pact_publication_ids
44
36
 
45
37
  # We only need to know if a webhook exists for an integration, not what its properties are
46
38
  webhooks = PactBroker::Webhooks::Webhook.select(:consumer_id, :provider_id).distinct.all
47
39
 
48
- pact_publication_ids = head_pact_publication_ids(options)
49
- pagination_record_count = pact_publication_ids.pagination_record_count
40
+ pact_publication_query = head_pact_publications(options)
41
+ pagination_record_count = pact_publication_query.pagination_record_count
50
42
 
51
- pact_publications = pact_publication_scope
52
- .where(id: pact_publication_ids)
53
- .select_all_qualified
43
+ pact_publications = pact_publication_query
54
44
  .eager(:consumer)
55
45
  .eager(:provider)
56
46
  .eager(:pact_version)
57
47
  .eager(integration: [{latest_verification: :provider_version}, :latest_triggered_webhooks])
58
- .eager(:consumer_version)
59
- .eager(latest_verification: { provider_version: :tags_with_latest_flag })
60
- .eager(:head_pact_tags)
48
+ .eager(consumer_version: [:latest_version_for_branch, { tags: :head_tag }])
49
+ .eager(latest_verification: { provider_version: [:latest_version_for_branch, { tags: :head_tag } ] })
50
+ .eager(:head_pact_publications_for_tags)
61
51
 
62
52
  index_items = pact_publications.all.collect do | pact_publication |
63
- is_overall_latest_for_integration = latest_pact_publication_ids.include?(pact_publication.id)
53
+ is_overall_latest_for_integration = latest_pp_ids.include?(pact_publication.id)
54
+
64
55
  latest_verification = latest_verification_for_pseudo_branch(pact_publication, is_overall_latest_for_integration, latest_verifications_for_cv_tags, options[:tags])
65
56
  webhook = webhooks.find{ |webhook| webhook.is_for?(pact_publication.integration) }
66
57
 
@@ -72,8 +63,9 @@ module PactBroker
72
63
  latest_verification,
73
64
  webhook ? [webhook]: [],
74
65
  pact_publication.integration.latest_triggered_webhooks,
75
- consumer_version_tags(pact_publication, options[:tags]),
76
- options[:tags] && latest_verification ? latest_verification.provider_version.tags_with_latest_flag.select(&:latest?) : []
66
+ consumer_version_tags(pact_publication, options[:tags]).sort_by(&:created_at).collect(&:name),
67
+ options[:tags] && latest_verification ? latest_verification.provider_version.tags.select(&:latest_for_pacticipant?).sort_by(&:created_at) : [],
68
+ pact_publication.latest_for_branch?
77
69
  )
78
70
  end.sort
79
71
 
@@ -98,32 +90,26 @@ module PactBroker
98
90
 
99
91
  def self.consumer_version_tags(pact_publication, tags_option)
100
92
  if tags_option == true
101
- pact_publication.head_pact_tags.collect(&:name)
93
+ pact_publication.head_pact_tags
102
94
  elsif tags_option.is_a?(Array)
103
- pact_publication.head_pact_tags.collect(&:name) & tags_option
95
+ pact_publication.head_pact_tags.select{ |tag| tags_option.include?(tag.name)}
104
96
  else
105
97
  []
106
98
  end
107
99
  end
108
100
 
109
101
  def self.find_index_items_for_api(consumer_name: nil, provider_name: nil, **ignored)
110
- latest_pact_publication_ids = latest_pact_publications.select(:id).all.collect{ |h| h[:id] }
111
- pact_publication_ids = head_pact_publication_ids(consumer_name: consumer_name, provider_name: provider_name, tags: true)
112
-
113
- pact_publications = pact_publication_scope
114
- .where(id: pact_publication_ids)
115
- .select_all_qualified
102
+ latest_pp_ids = latest_pact_publication_ids
103
+ pact_publications = head_pact_publications(consumer_name: consumer_name, provider_name: provider_name, tags: true)
116
104
  .eager(:consumer)
117
105
  .eager(:provider)
118
106
  .eager(:pact_version)
119
- .eager(:consumer_version)
120
- .eager(latest_verification: { provider_version: :tags_with_latest_flag })
121
- .eager(:head_pact_tags)
122
-
107
+ .eager(consumer_version: [:latest_version_for_branch, { tags: :head_tag }])
108
+ .eager(latest_verification: { provider_version: [:latest_version_for_branch, { tags: :head_tag }]})
109
+ .eager(:head_pact_publications_for_tags)
123
110
 
124
111
  pact_publications.all.collect do | pact_publication |
125
-
126
- is_overall_latest_for_integration = latest_pact_publication_ids.include?(pact_publication.id)
112
+ is_overall_latest_for_integration = latest_pp_ids.include?(pact_publication.id)
127
113
 
128
114
  PactBroker::Domain::IndexItem.create(
129
115
  pact_publication.consumer,
@@ -133,42 +119,62 @@ module PactBroker
133
119
  pact_publication.latest_verification,
134
120
  [],
135
121
  [],
136
- pact_publication.head_pact_tags.collect(&:name),
137
- pact_publication.latest_verification ? pact_publication.latest_verification.provider_version.tags_with_latest_flag.select(&:latest?) : []
122
+ pact_publication.head_pact_tags.sort_by(&:created_at).collect(&:name),
123
+ pact_publication.latest_verification ? pact_publication.latest_verification.provider_version.tags.select(&:latest_for_pacticipant?).sort_by(&:created_at) : []
138
124
  )
139
125
  end.sort
140
126
  end
141
127
 
142
128
  def self.latest_pact_publications
143
- db[:latest_pact_publications]
129
+ PactBroker::Pacts::PactPublication.overall_latest
130
+ end
131
+
132
+ def self.latest_pact_publication_ids
133
+ PactBroker::Pacts::PactPublication.select(Sequel[:pact_publications][:id]).overall_latest.collect(&:id)
144
134
  end
145
135
 
146
136
  def self.db
147
137
  PactBroker::Pacts::PactPublication.db
148
138
  end
149
139
 
150
- def self.head_pact_publication_ids(options = {})
151
- query = if options[:tags].is_a?(Array)
152
- LATEST_PPS.union(LATEST_TAGGED_PPS.where(tag_name: options[:tags]))
153
- elsif options[:tags]
154
- LATEST_PPS.union(LATEST_TAGGED_PPS)
155
- else
156
- LATEST_PPS
157
- end
140
+ def self.head_pact_publications(options = {})
141
+ base = PactBroker::Pacts::PactPublication.select(Sequel[:pact_publications][:id])
158
142
 
159
143
  if options[:consumer_name]
160
- query = query.where(PactBroker::Repositories::Helpers.name_like(:consumer_name, options[:consumer_name]))
144
+ consumer = pacticipant_repository.find_by_name!(options[:consumer_name])
145
+ base = base.for_consumer(consumer)
161
146
  end
162
147
 
163
148
  if options[:provider_name]
164
- query = query.where(PactBroker::Repositories::Helpers.name_like(:provider_name, options[:provider_name]))
149
+ provider = pacticipant_repository.find_by_name!(options[:provider_name])
150
+ base = base.for_provider(provider)
165
151
  end
166
152
 
167
- query.order(*HEAD_PP_ORDER_COLUMNS)
153
+ latest = base.overall_latest
154
+ ids_query = if options[:tags].is_a?(Array)
155
+ latest.union(base.latest_for_consumer_tag(options[:tags]))
156
+ elsif options[:tags]
157
+ latest.union(base.latest_by_consumer_tag)
158
+ else
159
+ latest
160
+ end
161
+
162
+ query = PactBroker::Pacts::PactPublication.select_all_qualified.where(Sequel[:pact_publications][:id] => ids_query)
163
+ .join_consumers(:consumers)
164
+ .join_providers(:providers)
165
+ .join(:versions, { Sequel[:pact_publications][:consumer_version_id] => Sequel[:cv][:id] }, { table_alias: :cv } )
166
+
167
+ order_columns = [
168
+ Sequel.asc(Sequel.function(:lower, Sequel[:consumers][:name])),
169
+ Sequel.desc(Sequel[:cv][:order]),
170
+ Sequel.asc(Sequel.function(:lower, Sequel[:providers][:name]))
171
+ ]
172
+
173
+ query.order(*order_columns)
168
174
  .paginate(options[:page_number] || DEFAULT_PAGE_NUMBER, options[:page_size] || DEFAULT_PAGE_SIZE)
169
- .select(:id)
170
175
  end
171
176
 
177
+ # eager loading the tag stuff doesn't seem to make it quicker
172
178
  def self.latest_verifications_for_consumer_version_tags(options)
173
179
  # server side rendered index page with tags[]=a&tags=[]b
174
180
  if options[:tags].is_a?(Array)
@@ -9,7 +9,8 @@ en:
9
9
  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"
10
10
  non_templated_host?: "cannot have a template parameter in the host"
11
11
  pacticipant_exists?: "does not match an existing pacticipant"
12
-
12
+ single_line?: "cannot contain multiple lines"
13
+ no_spaces?: "cannot contain spaces"
13
14
 
14
15
  pact_broker:
15
16
  messages:
@@ -46,6 +47,7 @@ en:
46
47
  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"
47
48
  invalid_webhook_uuid: The UUID can only contain the characters A-Z, a-z, 0-9, _ and -, and must be 16 or more characters.
48
49
  pacticipant_not_found: No pacticipant with name '%{name}' found
50
+ environment_name_must_be_unique: Another environment with name '%{name}' already exists.
49
51
  duplicate_pacticipant: |
50
52
  This is the first time a pact has been published for "%{new_name}".
51
53
  The name "%{new_name}" is very similar to the following existing consumers/providers:
@@ -351,6 +351,10 @@ module PactBroker
351
351
  consumer_version.number
352
352
  end
353
353
 
354
+ def consumer_version_branch
355
+ consumer_version.branch
356
+ end
357
+
354
358
  def consumer_version_order
355
359
  consumer_version.order
356
360
  end
@@ -363,6 +367,10 @@ module PactBroker
363
367
  provider_version&.number
364
368
  end
365
369
 
370
+ def provider_version_branch
371
+ provider_version&.branch
372
+ end
373
+
366
374
  def provider_version_order
367
375
  provider_version&.order
368
376
  end