pact_broker 2.51.0 → 2.52.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/db/migrations/20200318_add_created_at_to_latest_pact_publications.rb +9 -0
  4. data/db/migrations/20200319_add_created_at_to_latest_verifications.rb +9 -0
  5. data/lib/pact_broker/api/contracts/dry_validation_predicates.rb +4 -0
  6. data/lib/pact_broker/api/contracts/verifiable_pacts_json_query_schema.rb +26 -1
  7. data/lib/pact_broker/api/contracts/verifiable_pacts_query_schema.rb +2 -0
  8. data/lib/pact_broker/api/decorators/matrix_text_decorator.rb +1 -1
  9. data/lib/pact_broker/api/decorators/verifiable_pacts_query_decorator.rb +1 -0
  10. data/lib/pact_broker/api/pact_broker_urls.rb +11 -0
  11. data/lib/pact_broker/api/renderers/html_pact_renderer.rb +1 -1
  12. data/lib/pact_broker/db/data_migrations/set_created_at_for_latest_pact_publications.rb +25 -0
  13. data/lib/pact_broker/db/data_migrations/set_created_at_for_latest_verifications.rb +24 -0
  14. data/lib/pact_broker/db/migrate_data.rb +2 -0
  15. data/lib/pact_broker/matrix/every_row.rb +11 -5
  16. data/lib/pact_broker/matrix/parse_query.rb +6 -0
  17. data/lib/pact_broker/matrix/query_builder.rb +28 -16
  18. data/lib/pact_broker/matrix/query_results_with_deployment_status_summary.rb +15 -4
  19. data/lib/pact_broker/matrix/quick_row.rb +49 -65
  20. data/lib/pact_broker/matrix/repository.rb +2 -12
  21. data/lib/pact_broker/matrix/resolved_selector.rb +1 -1
  22. data/lib/pact_broker/matrix/service.rb +1 -1
  23. data/lib/pact_broker/pacts/pact_publication.rb +8 -0
  24. data/lib/pact_broker/pacts/repository.rb +10 -11
  25. data/lib/pact_broker/pacts/selector.rb +21 -0
  26. data/lib/pact_broker/pacts/verifiable_pact_messages.rb +5 -1
  27. data/lib/pact_broker/test/test_data_builder.rb +6 -0
  28. data/lib/pact_broker/ui/view_models/matrix_line.rb +8 -0
  29. data/lib/pact_broker/ui/views/matrix/show.haml +4 -4
  30. data/lib/pact_broker/verifications/repository.rb +2 -1
  31. data/lib/pact_broker/version.rb +1 -1
  32. data/lib/rack/pact_broker/request_target.rb +1 -1
  33. data/pact_broker.gemspec +1 -1
  34. data/public/javascripts/matrix.js +20 -8
  35. data/script/docker/db-restore.sh +1 -1
  36. data/spec/lib/pact_broker/api/contracts/verifiable_pacts_json_query_schema_spec.rb +43 -2
  37. data/spec/lib/pact_broker/api/contracts/verifiable_pacts_query_schema_spec.rb +13 -0
  38. data/spec/lib/pact_broker/api/decorators/matrix_decorator_spec.rb +11 -2
  39. data/spec/lib/pact_broker/api/renderers/html_pact_renderer_spec.rb +2 -1
  40. data/spec/lib/pact_broker/matrix/every_row_spec.rb +0 -10
  41. data/spec/lib/pact_broker/matrix/quick_row_spec.rb +11 -11
  42. data/spec/lib/pact_broker/matrix/repository_dependency_spec.rb +1 -1
  43. data/spec/lib/pact_broker/matrix/repository_spec.rb +9 -9
  44. data/spec/lib/pact_broker/pacts/repository_find_for_verification_spec.rb +43 -1
  45. data/spec/lib/pact_broker/pacts/repository_spec.rb +9 -0
  46. data/spec/lib/pact_broker/pacts/selector_spec.rb +5 -2
  47. data/spec/lib/pact_broker/pacts/verifiable_pact_messages_spec.rb +6 -0
  48. data/spec/lib/pact_broker/verifications/repository_spec.rb +21 -0
  49. metadata +10 -12
@@ -124,19 +124,9 @@ module PactBroker
124
124
  end
125
125
 
126
126
  def query_matrix selectors, options
127
- query = base_model(options)
128
- .select_all_columns
127
+ query = base_model(options).select_all_columns
129
128
  .matching_selectors(selectors)
130
-
131
- # These two could both probably use the order by last action date,
132
- # but I just want to give the implications a little more thought before changing
133
- # the can-i-deploy query order.
134
- if selectors.all?(&:only_pacticipant_name_specified?)
135
- # Can only be the UI, as can-i-deploy requires a version to be specified
136
- query = query.order_by_last_action_date
137
- else
138
- query = query.order_by_names_ascending_most_recent_first
139
- end
129
+ .order_by_last_action_date
140
130
 
141
131
  query = query.limit(options[:limit]) if options[:limit]
142
132
  query.eager_all_the_things.all
@@ -80,7 +80,7 @@ module PactBroker
80
80
  end
81
81
 
82
82
  def only_pacticipant_name_specified?
83
- pacticipant_name && !tag && !latest?
83
+ pacticipant_name && !tag && !latest? && !pacticipant_version_number
84
84
  end
85
85
 
86
86
  def latest_tagged?
@@ -13,7 +13,7 @@ module PactBroker
13
13
  def find selectors, options = {}
14
14
  query_results = matrix_repository.find selectors, options
15
15
  deployment_status_summary = DeploymentStatusSummary.new(query_results.rows, query_results.resolved_selectors, query_results.integrations)
16
- QueryResultsWithDeploymentStatusSummary.new(query_results.rows, query_results.selectors, query_results.options, query_results.resolved_selectors, query_results.integrations, deployment_status_summary)
16
+ QueryResultsWithDeploymentStatusSummary.new(query_results, deployment_status_summary)
17
17
  end
18
18
 
19
19
  def find_for_consumer_and_provider params, options = {}
@@ -82,6 +82,14 @@ module PactBroker
82
82
  def order_by_consumer_version_order
83
83
  order_append(Sequel[:cv][:order])
84
84
  end
85
+
86
+ def where_consumer_if_set(consumer)
87
+ if consumer
88
+ where(consumer: consumer)
89
+ else
90
+ self
91
+ end
92
+ end
85
93
  end
86
94
 
87
95
  def before_create
@@ -79,7 +79,8 @@ module PactBroker
79
79
  provider_id: pact_publication.provider_id,
80
80
  pact_publication_id: pact_publication.id,
81
81
  consumer_id: pact_publication.consumer_id,
82
- pact_version_id: pact_publication.pact_version_id
82
+ pact_version_id: pact_publication.pact_version_id,
83
+ created_at: pact_publication.consumer_version.created_at
83
84
  }
84
85
 
85
86
  LatestPactPublicationIdForConsumerVersion.new(params).upsert
@@ -130,8 +131,9 @@ module PactBroker
130
131
  end
131
132
  end
132
133
 
133
- def find_all_pact_versions_for_provider_with_consumer_version_tags provider_name, consumer_version_tag_names
134
+ def find_all_pact_versions_for_provider_with_consumer_version_tags provider_name, selector
134
135
  provider = pacticipant_repository.find_by_name(provider_name)
136
+ consumer = selector.consumer ? pacticipant_repository.find_by_name(selector.consumer) : nil
135
137
 
136
138
  PactPublication
137
139
  .select_all_qualified
@@ -139,8 +141,9 @@ module PactBroker
139
141
  .select_append(Sequel[:ct][:name].as(:consumer_version_tag_name))
140
142
  .remove_overridden_revisions
141
143
  .join_consumer_versions(:cv)
142
- .join_consumer_version_tags_with_names(consumer_version_tag_names)
144
+ .join_consumer_version_tags_with_names(selector.tag)
143
145
  .where(provider: provider)
146
+ .where_consumer_if_set(consumer)
144
147
  .eager(:consumer)
145
148
  .eager(:consumer_version)
146
149
  .eager(:provider)
@@ -149,10 +152,8 @@ module PactBroker
149
152
  .group_by(&:pact_version_id)
150
153
  .values
151
154
  .collect do | pact_publications |
152
- selector_tag_names = pact_publications.collect{ | p| p.values.fetch(:consumer_version_tag_name) }
153
155
  latest_pact_publication = pact_publications.sort_by{ |p| p.values.fetch(:consumer_version_order) }.last
154
- selectors = Selectors.create_for_all_of_each_tag(selector_tag_names)
155
- SelectedPact.new(latest_pact_publication.to_domain, selectors)
156
+ SelectedPact.new(latest_pact_publication.to_domain, Selectors.new(selector))
156
157
  end
157
158
  end
158
159
 
@@ -457,12 +458,10 @@ module PactBroker
457
458
 
458
459
  def find_pacts_for_which_all_versions_for_the_tag_are_required(provider_name, consumer_version_selectors)
459
460
  # The tags for which all versions are specified
460
- tag_names = consumer_version_selectors.tag_names_of_selectors_for_all_pacts
461
+ selectors = consumer_version_selectors.select(&:all_for_tag?)
461
462
 
462
- if tag_names.any?
463
- find_all_pact_versions_for_provider_with_consumer_version_tags(provider_name, tag_names)
464
- else
465
- []
463
+ selectors.flat_map do | selector |
464
+ find_all_pact_versions_for_provider_with_consumer_version_tags(provider_name, selector)
466
465
  end
467
466
  end
468
467
 
@@ -25,6 +25,14 @@ module PactBroker
25
25
  self[:fallback_tag]
26
26
  end
27
27
 
28
+ def consumer= consumer
29
+ self[:consumer] = consumer
30
+ end
31
+
32
+ def consumer
33
+ self[:consumer]
34
+ end
35
+
28
36
  def self.overall_latest
29
37
  Selector.new(latest: true)
30
38
  end
@@ -41,6 +49,9 @@ module PactBroker
41
49
  Selector.new(tag: tag)
42
50
  end
43
51
 
52
+ def self.all_for_tag_and_consumer(tag, consumer)
53
+ Selector.new(tag: tag, consumer: consumer)
54
+ end
44
55
 
45
56
  def self.from_hash hash
46
57
  Selector.new(hash)
@@ -67,6 +78,10 @@ module PactBroker
67
78
  end
68
79
  end
69
80
 
81
+ def all_for_tag_and_consumer?
82
+ !!(tag && !latest? && consumer)
83
+ end
84
+
70
85
  def all_for_tag?
71
86
  !!(tag && !latest?)
72
87
  end
@@ -84,6 +99,12 @@ module PactBroker
84
99
  else
85
100
  latest_for_tag? ? -1 : 1
86
101
  end
102
+ elsif consumer || other.consumer
103
+ if consumer == other.consumer
104
+ tag <=> other.tag
105
+ else
106
+ consumer ? -1 : 1
107
+ end
87
108
  else
88
109
  tag <=> other.tag
89
110
  end
@@ -138,7 +138,9 @@ module PactBroker
138
138
  else
139
139
  "latest pact for a consumer version tagged '#{selector.tag}'"
140
140
  end
141
- elsif selector.tag
141
+ elsif selector.all_for_tag_and_consumer?
142
+ "pacts for all #{selector.consumer} versions tagged '#{selector.tag}'"
143
+ elsif selector.all_for_tag?
142
144
  "pacts for all consumer versions tagged '#{selector.tag}'"
143
145
  else
144
146
  selector.to_json
@@ -159,6 +161,8 @@ module PactBroker
159
161
  else
160
162
  "latest #{selector.tag}"
161
163
  end
164
+ elsif selector.all_for_tag_and_consumer?
165
+ "one of #{selector.consumer} #{selector.tag}"
162
166
  elsif selector.tag
163
167
  "one of #{selector.tag}"
164
168
  else
@@ -213,6 +213,7 @@ module PactBroker
213
213
  )
214
214
  set_created_at_if_set(params[:created_at], :pact_publications, id: @pact.id)
215
215
  set_created_at_if_set(params[:created_at], :pact_versions, sha: @pact.pact_version_sha)
216
+ set_created_at_if_set(params[:created_at], :latest_pact_publication_ids_for_consumer_versions, consumer_version_id: @consumer_version.id)
216
217
  @pact = PactBroker::Pacts::PactPublication.find(id: @pact.id).to_domain
217
218
  self
218
219
  end
@@ -322,6 +323,7 @@ module PactBroker
322
323
 
323
324
  set_created_at_if_set(parameters[:created_at], :verifications, id: @verification.id)
324
325
  set_created_at_if_set(parameters[:created_at], :versions, id: @provider_version.id)
326
+ set_created_at_if_set(parameters[:created_at], :latest_verification_id_for_pact_version_and_provider_version, pact_version_id: pact_version_id, provider_version_id: @provider_version.id)
325
327
 
326
328
  if tag_names.any?
327
329
  tag_names.each do | tag_name |
@@ -406,6 +408,10 @@ module PactBroker
406
408
 
407
409
  private
408
410
 
411
+ def pact_version_id
412
+ PactBroker::Pacts::PactPublication.find(id: @pact.id).pact_version_id
413
+ end
414
+
409
415
  # Remember! This must be called before adding the IDs
410
416
  def generate_pact_version_sha json_content
411
417
  PactBroker.configuration.sha_generator.call(json_content)
@@ -50,6 +50,14 @@ module PactBroker
50
50
  @line.pact_revision_number
51
51
  end
52
52
 
53
+ def consumer_version_id
54
+ @line.consumer_version_id
55
+ end
56
+
57
+ def provider_version_id
58
+ @line.provider_version_id
59
+ end
60
+
53
61
  def consumer_version_number
54
62
  @line.consumer_version_number
55
63
  end
@@ -99,10 +99,10 @@
99
99
  %tbody
100
100
  - lines.each do | line |
101
101
  %tr
102
- %td.consumer{'data-sort-value' => line.consumer_name}
102
+ %td.consumer{'data-sort-value' => line.consumer_name, 'data-consumer-name' => line.consumer_name}
103
103
  %a{href: line.consumer_name_url}
104
104
  = line.consumer_name
105
- %td.consumer-version{'data-sort-value' => line.consumer_version_order}
105
+ %td.consumer-version{'data-sort-value' => line.consumer_version_order, 'data-consumer-version-id' => line.consumer_version_id}
106
106
  %div.clippable
107
107
  %a{href: line.consumer_version_number_url}
108
108
  = line.display_consumer_version_number
@@ -126,10 +126,10 @@
126
126
  - else
127
127
  = line.pact_publication_date
128
128
 
129
- %td.provider{'data-sort-value' => line.provider_name}
129
+ %td.provider{'data-sort-value' => line.provider_name, 'data-provider-name' => line.provider_name }
130
130
  %a{href: line.provider_name_url}
131
131
  = line.provider_name
132
- %td.provider-version{'data-sort-value' => line.provider_version_order}
132
+ %td.provider-version{'data-sort-value' => line.provider_version_order, 'data-provider-version-id' => line.provider_version_id }
133
133
  %div.clippable
134
134
  %a{href: line.provider_version_number_url}
135
135
  = line.display_provider_version_number
@@ -43,7 +43,8 @@ module PactBroker
43
43
  provider_version_id: verification.provider_version_id,
44
44
  provider_id: verification.provider_version.pacticipant_id,
45
45
  verification_id: verification.id,
46
- consumer_id: verification.consumer_id
46
+ consumer_id: verification.consumer_id,
47
+ created_at: verification.created_at
47
48
  }
48
49
  LatestVerificationIdForPactVersionAndProviderVersion.new(params).upsert
49
50
  end
@@ -1,3 +1,3 @@
1
1
  module PactBroker
2
- VERSION = '2.51.0'
2
+ VERSION = '2.52.0'
3
3
  end
@@ -6,7 +6,7 @@ module Rack
6
6
  extend self
7
7
 
8
8
  WEB_ASSET_EXTENSIONS = %w[.js .woff .woff2 .css .png .html .map .ttf .ico].freeze
9
- API_CONTENT_TYPES = %w[application/hal+json application/json text/csv application/yaml].freeze
9
+ API_CONTENT_TYPES = %w[application/hal+json application/json text/csv application/yaml text/plain].freeze
10
10
 
11
11
  def request_for_ui?(env)
12
12
  !(request_for_api?(env))
data/pact_broker.gemspec CHANGED
@@ -44,7 +44,7 @@ Gem::Specification.new do |gem|
44
44
 
45
45
  #gem.add_runtime_dependency 'pact'
46
46
  gem.add_runtime_dependency 'httparty', '~> 0.14'
47
- gem.add_runtime_dependency 'json', '> 1.8', '< 3.0'
47
+ gem.add_runtime_dependency 'json', '~> 2.3'
48
48
  gem.add_runtime_dependency 'roar', '~> 1.1'
49
49
  gem.add_runtime_dependency 'reform', '~> 2.2'
50
50
  gem.add_runtime_dependency 'dry-validation', '~> 0.10.5'
@@ -53,12 +53,12 @@ function disableFieldsThatShouldNotBeSubmitted() {
53
53
  $('.version-selectorizor').prop('disabled', 'disabled');
54
54
  }
55
55
 
56
- function highlightPactPublicationsWithSameContent(td) {
57
- const pactVersionSha = $(td).data('pact-version-sha');
58
- $('*[data-pact-version-sha="' + pactVersionSha +'"]').addClass('bg-info');
56
+ function highlightPactPublicationsWithSameData(td, field) {
57
+ const value = $(td).data(field);
58
+ $('*[data-' + field + '="' + value +'"]').addClass('bg-info');
59
59
  }
60
60
 
61
- function unHighlightPactPublicationsWithSameContent(td, event) {
61
+ function unHighlightPactPublicationsWithSameData(td, event, field) {
62
62
  var destinationElement = $(event.toElement || event.relatedTarget);
63
63
  // Have to use mouseout instead of mouseleave, because the tooltip is a child
64
64
  // of the td, and the mouseleave will consider that hovering over the tooltip
@@ -68,8 +68,8 @@ function unHighlightPactPublicationsWithSameContent(td, event) {
68
68
  // The tooltip needs to be a child of the td so that we can style the one showing
69
69
  // the SHA so that it's wide enough to fit the SHA in.
70
70
  if (!$(td).find('a').is(destinationElement)) {
71
- const pactVersionSha = $(td).data('pact-version-sha');
72
- $('*[data-pact-version-sha="' + pactVersionSha +'"]').removeClass('bg-info');
71
+ const value = $(td).data(field);
72
+ $('*[data-' + field + '="' + value +'"]').removeClass('bg-info');
73
73
  }
74
74
  }
75
75
 
@@ -90,6 +90,18 @@ $(document).ready(function(){
90
90
 
91
91
  initializeClipper('.clippable');
92
92
 
93
- $('td.pact-published').mouseover(function(event) { highlightPactPublicationsWithSameContent(this) });
94
- $('td.pact-published').mouseout(function(event) { unHighlightPactPublicationsWithSameContent(this, event)});
93
+ $('td.consumer').mouseover(function(event) { highlightPactPublicationsWithSameData(this, 'consumer-name') });
94
+ $('td.consumer').mouseout(function(event) { unHighlightPactPublicationsWithSameData(this, event, 'consumer-name') });
95
+
96
+ $('td.consumer-version').mouseover(function(event) { highlightPactPublicationsWithSameData(this, 'consumer-version-id') });
97
+ $('td.consumer-version').mouseout(function(event) { unHighlightPactPublicationsWithSameData(this, event, 'consumer-version-id') });
98
+
99
+ $('td.pact-published').mouseover(function(event) { highlightPactPublicationsWithSameData(this, 'pact-version-sha') });
100
+ $('td.pact-published').mouseout(function(event) { unHighlightPactPublicationsWithSameData(this, event, 'pact-version-sha') });
101
+
102
+ $('td.provider').mouseover(function(event) { highlightPactPublicationsWithSameData(this, 'provider-name') });
103
+ $('td.provider').mouseout(function(event) { unHighlightPactPublicationsWithSameData(this, event, 'provider-name') });
104
+
105
+ $('td.provider-version').mouseover(function(event) { highlightPactPublicationsWithSameData(this, 'provider-version-id') });
106
+ $('td.provider-version').mouseout(function(event) { unHighlightPactPublicationsWithSameData(this, event, 'provider-version-id') });
95
107
  });
@@ -2,4 +2,4 @@
2
2
 
3
3
  : "${1:?Please specify file to restore}"
4
4
 
5
- docker exec -it pact-broker-postgres pg_restore -h localhost -U postgres -d postgres /data/$1
5
+ docker exec -it pact-broker-postgres pg_restore -h localhost -U postgres -d postgres --clean --if-exists /data/$1
@@ -43,7 +43,7 @@ module PactBroker
43
43
  end
44
44
  end
45
45
 
46
- context "when latest is not specified", pending: true do
46
+ context "when latest is not specified" do
47
47
  let(:consumer_version_selectors) do
48
48
  [{
49
49
  tag: "feat-x",
@@ -52,7 +52,21 @@ module PactBroker
52
52
  end
53
53
 
54
54
  it "has an error" do
55
- expect(subject[:consumerVersionSelectors].first).to include "not allowed"
55
+ expect(subject[:consumerVersionSelectors].first).to match /can only be set.*index 0/
56
+ end
57
+
58
+ context "when there are multiple errors" do
59
+ let(:consumer_version_selectors) do
60
+ [{
61
+ consumer: "",
62
+ tag: "feat-x",
63
+ fallbackTag: "master"
64
+ }]
65
+ end
66
+
67
+ it "merges the array" do
68
+ expect(subject[:consumerVersionSelectors].size).to be 2
69
+ end
56
70
  end
57
71
  end
58
72
  end
@@ -113,6 +127,33 @@ module PactBroker
113
127
  it { is_expected.to_not have_key(:includeWipPactsSince) }
114
128
  end
115
129
  end
130
+
131
+ context "when a blank consumer name is specified" do
132
+ let(:consumer_version_selectors) do
133
+ [{
134
+ tag: "feat-x",
135
+ consumer: ""
136
+ }]
137
+ end
138
+
139
+ it "has an error" do
140
+ expect(subject[:consumerVersionSelectors].first).to include "blank"
141
+ end
142
+ end
143
+
144
+ context "when a consumer name is specified with a latest tag" do
145
+ let(:consumer_version_selectors) do
146
+ [{
147
+ latest: true,
148
+ tag: "feat-x",
149
+ consumer: "foo"
150
+ }]
151
+ end
152
+
153
+ it "has an error" do
154
+ expect(subject[:consumerVersionSelectors].first).to include "not yet supported"
155
+ end
156
+ end
116
157
  end
117
158
  end
118
159
  end
@@ -78,6 +78,19 @@ module PactBroker
78
78
  it { is_expected.to_not have_key(:include_wip_pacts_since) }
79
79
  end
80
80
  end
81
+
82
+ context "when a blank consumer name is specified" do
83
+ let(:consumer_version_selectors) do
84
+ [{
85
+ tag: "feat-x",
86
+ consumer: ""
87
+ }]
88
+ end
89
+
90
+ it "has an error" do
91
+ expect(subject[:consumer_version_selectors].first).to include "blank"
92
+ end
93
+ end
81
94
  end
82
95
  end
83
96
  end
@@ -135,7 +135,16 @@ module PactBroker
135
135
  ]
136
136
  end
137
137
 
138
- let(:query_results){ PactBroker::Matrix::QueryResultsWithDeploymentStatusSummary.new([row_1, row_2], selectors, options, resolved_selectors, integrations, deployment_status_summary)}
138
+ let(:query_results) do
139
+ double('QueryResults',
140
+ rows: [row_1, row_2],
141
+ selectors: selectors,
142
+ options: options,
143
+ resolved_selectors: resolved_selectors,
144
+ integrations: integrations
145
+ )
146
+ end
147
+ let(:query_results_with_deployment_status_summary){ PactBroker::Matrix::QueryResultsWithDeploymentStatusSummary.new(query_results, deployment_status_summary)}
139
148
  let(:selectors) { nil }
140
149
  let(:integrations){ [] }
141
150
  let(:options) { nil }
@@ -145,7 +154,7 @@ module PactBroker
145
154
  instance_double('PactBroker::Matrix::DeploymentStatusSummary', reasons: ['foo', 'bar'], deployable?: deployable, counts: counts)
146
155
  end
147
156
  let(:deployable) { true }
148
- let(:json) { MatrixDecorator.new(query_results).to_json(user_options: { base_url: 'http://example.org' }) }
157
+ let(:json) { MatrixDecorator.new(query_results_with_deployment_status_summary).to_json(user_options: { base_url: 'http://example.org' }) }
149
158
  let(:parsed_json) { JSON.parse(json, symbolize_names: true) }
150
159
 
151
160
  it "includes the consumer details" do