pact_broker 2.46.0 → 2.47.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4afa0b6a3444f1fdf6ea852bed8016f63cccd1a5373aa0903be0d206f528bc6
4
- data.tar.gz: cd86a0d032bb39ffe2f4318116cc9e51886fc3d3e84bf8c537d6bae5ee0f9d52
3
+ metadata.gz: c54fb8ff19038af9dd5d0a09105244459a18febe23333bf5203ef77424eb97a3
4
+ data.tar.gz: f380f9f5e9939d9844e88f09b5807a5e1f094cc368adfa22c104ee8ad55d9f97
5
5
  SHA512:
6
- metadata.gz: 217a6da9c4b27d6959695eefa1c6b8c13526c827222d114cb6527d20fc9fceec194498ffa84ee6f10e574f96a353429bfdacf18f6b6494826e12aea5d58fc7ba
7
- data.tar.gz: 1632aac1111449205a45ca9367093d2e4557e75a163a8c516248486f7a7e884cbf9205302ba8c5e1f4c01c8ff604bbebdaeef6729a1bc03e9dd97ec7f0afa850
6
+ metadata.gz: ebfc52497d4d877c0adb715bd1bf39c1be9513893ffaf032e142d160b4aa12be04c5b01d0c698f7b94ea6aadca1a416cddd53e3a0f304bb9c2821d128cf894a2
7
+ data.tar.gz: 41184e2249f9bde504a6f9258bf44ff2f33a8374d6a2d05ebe59536c8113461c79f41319a9b337f1db58c83e31ff652951ffca7466988626150dab7e09002abb
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ <a name="v2.47.0"></a>
2
+ ### v2.47.0 (2020-01-31)
3
+
4
+
5
+ #### Features
6
+
7
+ * include the webhook context in the execution logs ([29f65bef](/../../commit/29f65bef))
8
+
9
+
1
10
  <a name="v2.46.0"></a>
2
11
  ### v2.46.0 (2020-01-30)
3
12
 
data/Dockerfile CHANGED
@@ -12,6 +12,7 @@ RUN apk update \
12
12
  "sqlite>=3.28" \
13
13
  "tzdata>=2019" \
14
14
  "mariadb-dev>=10.3" \
15
+ "git" \
15
16
  && rm -rf /var/cache/apk/*
16
17
 
17
18
  WORKDIR /app
@@ -40,7 +40,10 @@ module PactBroker
40
40
  provider_name,
41
41
  parsed_query_params.provider_version_tags,
42
42
  parsed_query_params.consumer_version_selectors,
43
- { include_wip_pacts_since: parsed_query_params.include_wip_pacts_since }
43
+ {
44
+ include_wip_pacts_since: parsed_query_params.include_wip_pacts_since,
45
+ include_pending_status: parsed_query_params.include_pending_status
46
+ }
44
47
  )
45
48
  end
46
49
 
@@ -33,11 +33,11 @@ module PactBroker
33
33
  end
34
34
 
35
35
  def to_json
36
- decorator_for(verification).to_json(user_options: {base_url: base_url})
36
+ decorator_for(verification).to_json(user_options: { base_url: base_url })
37
37
  end
38
38
 
39
39
  def to_extended_json
40
- extended_decorator_for(verification).to_json(user_options: {base_url: base_url})
40
+ extended_decorator_for(verification).to_json(user_options: { base_url: base_url })
41
41
  end
42
42
 
43
43
  private
@@ -49,7 +49,7 @@ module PactBroker
49
49
 
50
50
  def from_json
51
51
  verification = verification_service.create(next_verification_number, params_with_string_keys, pact, webhook_options)
52
- response.body = decorator_for(verification).to_json(user_options: {base_url: base_url})
52
+ response.body = decorator_for(verification).to_json(user_options: { base_url: base_url })
53
53
  true
54
54
  end
55
55
 
@@ -53,14 +53,14 @@ module PactBroker
53
53
  end
54
54
 
55
55
  def execute pact, verification, options
56
- logger.info "Executing #{self}"
56
+ logger.info "Executing #{self} webhook_context=#{options.fetch(:webhook_context)}"
57
57
  webhook_request = request.build(template_parameters(pact, verification, options))
58
58
  http_response, error = execute_request(webhook_request)
59
59
 
60
60
  PactBroker::Webhooks::WebhookExecutionResult.new(
61
61
  webhook_request.http_request,
62
62
  http_response,
63
- generate_logs(webhook_request, http_response, error, options.fetch(:logging_options)),
63
+ generate_logs(webhook_request, http_response, error, options[:webhook_context], options.fetch(:logging_options)),
64
64
  error
65
65
  )
66
66
  end
@@ -110,13 +110,14 @@ module PactBroker
110
110
  PactBroker::Webhooks::PactAndVerificationParameters.new(pact, verification, options.fetch(:webhook_context)).to_hash
111
111
  end
112
112
 
113
- def generate_logs(webhook_request, http_response, error, logging_options)
113
+ def generate_logs(webhook_request, http_response, error, webhook_context, logging_options)
114
114
  webhook_request_logger = PactBroker::Webhooks::WebhookRequestLogger.new(logging_options)
115
115
  webhook_request_logger.log(
116
116
  uuid,
117
117
  webhook_request,
118
118
  http_response,
119
- error
119
+ error,
120
+ webhook_context
120
121
  )
121
122
  end
122
123
  end
@@ -14,6 +14,8 @@ require 'pact_broker/matrix/head_row'
14
14
  require 'pact_broker/pacts/latest_pact_publication_id_for_consumer_version'
15
15
  require 'pact_broker/pacts/verifiable_pact'
16
16
  require 'pact_broker/repositories/helpers'
17
+ require 'pact_broker/pacts/selected_pact'
18
+ require 'pact_broker/pacts/selector'
17
19
 
18
20
  module PactBroker
19
21
  module Pacts
@@ -127,12 +129,13 @@ module PactBroker
127
129
  end
128
130
  end
129
131
 
130
- def find_all_pact_versions_for_provider_with_tags provider_name, consumer_version_tag_names
132
+ def find_all_pact_versions_for_provider_with_consumer_version_tags provider_name, consumer_version_tag_names
131
133
  provider = pacticipant_repository.find_by_name(provider_name)
132
134
 
133
135
  PactPublication
134
136
  .select_all_qualified
135
137
  .select_append(Sequel[:cv][:order].as(:consumer_version_order))
138
+ .select_append(Sequel[:ct][:name].as(:consumer_version_tag_name))
136
139
  .remove_overridden_revisions
137
140
  .join_consumer_versions(:cv)
138
141
  .join_consumer_version_tags_with_names(consumer_version_tag_names)
@@ -144,8 +147,12 @@ module PactBroker
144
147
  .all
145
148
  .group_by(&:pact_version_id)
146
149
  .values
147
- .collect{ | pacts| pacts.sort_by{|pact| pact.values.fetch(:consumer_version_order) }.last }
148
- .collect(&:to_domain)
150
+ .collect do | pact_publications |
151
+ selector_tag_names = pact_publications.collect{ | p| p.values.fetch(:consumer_version_tag_name) }
152
+ latest_pact_publication = pact_publications.sort_by{ |p| p.values.fetch(:consumer_version_order) }.last
153
+ selectors = selector_tag_names.collect{ | tag_name | Selector.one_of_tag(tag_name) }
154
+ SelectedPact.new(latest_pact_publication.to_domain, selectors)
155
+ end
149
156
  end
150
157
 
151
158
  # To find the work in progress pacts for this verification execution:
@@ -339,29 +346,67 @@ module PactBroker
339
346
 
340
347
  # Returns a list of Domain::Pact objects the represent pact publications
341
348
  def find_for_verification(provider_name, consumer_version_selectors)
342
- find_pacts_for_which_the_latest_version_or_latest_version_for_the_tag_is_required(provider_name, consumer_version_selectors) +
349
+ selected_pacts = find_pacts_for_which_the_latest_version_is_required(provider_name, consumer_version_selectors) +
350
+ find_pacts_for_which_the_latest_version_for_the_tag_is_required(provider_name, consumer_version_selectors) +
343
351
  find_pacts_for_which_all_versions_for_the_tag_are_required(provider_name, consumer_version_selectors)
352
+ selected_pacts
353
+ .group_by(&:pact_version_sha)
354
+ .values
355
+ .collect do | selected_pacts_for_pact_version_id |
356
+ SelectedPact.merge(selected_pacts_for_pact_version_id)
357
+ end
344
358
  end
345
359
 
346
360
  private
347
361
 
348
- def find_pacts_for_which_the_latest_version_or_latest_version_for_the_tag_is_required(provider_name, consumer_version_selectors)
362
+ def find_pacts_for_which_the_latest_version_is_required(provider_name, consumer_version_selectors)
363
+ if consumer_version_selectors.empty?
364
+ LatestPactPublications
365
+ .provider(provider_name)
366
+ .order_ignore_case(:consumer_name)
367
+ .collect do | latest_pact_publication |
368
+ pact_publication = PactPublication.find(id: latest_pact_publication.id)
369
+ SelectedPact.new(pact_publication.to_domain, [Selector.overall_latest])
370
+ end
371
+ else
372
+ []
373
+ end
374
+ end
375
+
376
+ def find_pacts_for_which_the_latest_version_for_the_tag_is_required(provider_name, consumer_version_selectors)
349
377
  # The tags for which only the latest version is specified
350
- latest_tags = consumer_version_selectors.any? ?
351
- consumer_version_selectors.select(&:latest).collect(&:tag) :
352
- nil
378
+ latest_tags = consumer_version_selectors.select(&:latest).collect(&:tag).compact.uniq
353
379
 
354
- find_latest_pact_versions_for_provider(provider_name, latest_tags)
380
+ # TODO make this an efficient query!
381
+ # These are not yet de-duped. Should make the behaviour consistent between this and find_pacts_for_which_all_versions_for_the_tag_are_required ?
382
+ if latest_tags.any?
383
+ LatestTaggedPactPublications
384
+ .provider(provider_name)
385
+ .order_ignore_case(:consumer_name)
386
+ .where(tag_name: latest_tags)
387
+ .all
388
+ .group_by(&:pact_version_id)
389
+ .values
390
+ .collect do | pact_publications |
391
+ selector_tag_names = pact_publications.collect(&:tag_name)
392
+ last_pact_publication = pact_publications.sort_by(&:consumer_version_order).last
393
+ pact_publication = PactPublication.find(id: last_pact_publication.id)
394
+ SelectedPact.new(
395
+ pact_publication.to_domain,
396
+ selector_tag_names.collect{ | tag_name| Selector.latest_for_tag(tag_name) }
397
+ )
398
+ end
399
+ else
400
+ []
401
+ end
355
402
  end
356
403
 
357
404
  def find_pacts_for_which_all_versions_for_the_tag_are_required(provider_name, consumer_version_selectors)
358
405
  # The tags for which all versions are specified
359
- all_tags = consumer_version_selectors.any? ?
360
- consumer_version_selectors.reject(&:latest).collect(&:tag) :
361
- nil
406
+ all_tags = consumer_version_selectors.reject(&:latest).collect(&:tag)
362
407
 
363
- if all_tags
364
- find_all_pact_versions_for_provider_with_tags(provider_name, all_tags)
408
+ if all_tags.any?
409
+ find_all_pact_versions_for_provider_with_consumer_version_tags(provider_name, all_tags)
365
410
  else
366
411
  []
367
412
  end
@@ -0,0 +1,46 @@
1
+ require 'delegate'
2
+
3
+ module PactBroker
4
+ module Pacts
5
+ class SelectedPact < SimpleDelegator
6
+ attr_reader :pact, :selectors
7
+
8
+ def initialize(pact, selectors)
9
+ super(pact)
10
+ @pact = pact
11
+ @selectors = selectors
12
+ end
13
+
14
+ # might actually be, but this code doesn't know it.
15
+ def overall_latest?
16
+ selectors.any?(&:overall_latest?)
17
+ end
18
+
19
+ def latest_for_tag?
20
+ selectors.any?(&:latest_for_tag?)
21
+ end
22
+
23
+ def self.merge(selected_pacts)
24
+ latest_selected_pact = selected_pacts.sort_by(&:consumer_version_order).last
25
+ selectors = selected_pacts.collect(&:selectors).flatten.uniq
26
+ SelectedPact.new(latest_selected_pact.pact, selectors)
27
+ end
28
+
29
+ def merge(other)
30
+ if pact_version_sha != other.pact_version_sha
31
+ raise "These two pacts do not have the same pact_version_sha. They cannot be merged. #{pact_version_sha} and #{other.pact_version_sha}"
32
+ else
33
+ SelectedPact.new()
34
+ end
35
+ end
36
+
37
+ def tag_names_for_selectors_for_latest_pacts
38
+ selectors.select(&:latest_for_tag?).collect(&:tag)
39
+ end
40
+
41
+ def consumer_version_order
42
+ pact.consumer_version.order
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,43 @@
1
+ module PactBroker
2
+ module Pacts
3
+ class Selector < Hash
4
+ def initialize(options)
5
+ merge!(options)
6
+ end
7
+
8
+ def self.overall_latest
9
+ Selector.new(latest: true)
10
+ end
11
+
12
+ def self.latest_for_tag(tag)
13
+ Selector.new(latest: true, tag: tag)
14
+ end
15
+
16
+ def self.one_of_tag(tag)
17
+ Selector.new(tag: tag)
18
+ end
19
+
20
+ def tag
21
+ self[:tag]
22
+ end
23
+
24
+ def overall_latest?
25
+ !!(latest && !tag)
26
+ end
27
+
28
+ def latest_for_tag?
29
+ !!(latest && tag)
30
+ end
31
+
32
+ private
33
+
34
+ def latest?
35
+ self[:latest]
36
+ end
37
+
38
+ def latest
39
+ self[:latest]
40
+ end
41
+ end
42
+ end
43
+ end
@@ -118,10 +118,8 @@ module PactBroker
118
118
  def find_for_verification(provider_name, provider_version_tags, consumer_version_selectors, options)
119
119
  verifiable_pacts_specified_in_request = pact_repository
120
120
  .find_for_verification(provider_name, consumer_version_selectors)
121
- .group_by(&:pact_version_sha)
122
- .values
123
- .collect do | head_pacts |
124
- squash_pacts_for_verification(provider_version_tags, head_pacts)
121
+ .collect do | selected_pact |
122
+ squash_pacts_for_verification(provider_version_tags, selected_pact, options[:include_pending_status])
125
123
  end
126
124
 
127
125
  verifiable_wip_pacts = if options[:include_wip_pacts_since]
@@ -5,28 +5,38 @@
5
5
  module PactBroker
6
6
  module Pacts
7
7
  module SquashPactsForVerification
8
- def self.call(provider_version_tags, head_pacts)
9
- domain_pact = head_pacts.first.pact
10
- pending_provider_tags = []
11
- pending = nil
12
- if provider_version_tags.any?
13
- pending_provider_tags = domain_pact.select_pending_provider_version_tags(provider_version_tags)
14
- pending = pending_provider_tags.any?
8
+ def self.call(provider_version_tags, selected_pact, include_pending_status = false)
9
+ domain_pact = selected_pact.pact
10
+
11
+ if include_pending_status
12
+ pending_provider_tags = []
13
+ non_pending_provider_tags = []
14
+ pending = nil
15
+ if provider_version_tags.any?
16
+ pending_provider_tags = domain_pact.select_pending_provider_version_tags(provider_version_tags)
17
+ pending = pending_provider_tags.any?
18
+ else
19
+ pending = domain_pact.pending?
20
+ end
21
+ non_pending_provider_tags = provider_version_tags - pending_provider_tags
22
+ VerifiablePact.new(
23
+ domain_pact,
24
+ pending,
25
+ pending_provider_tags,
26
+ non_pending_provider_tags,
27
+ selected_pact.tag_names_for_selectors_for_latest_pacts,
28
+ selected_pact.overall_latest?
29
+ )
15
30
  else
16
- pending = domain_pact.pending?
31
+ VerifiablePact.new(
32
+ domain_pact,
33
+ nil,
34
+ [],
35
+ [],
36
+ selected_pact.tag_names_for_selectors_for_latest_pacts,
37
+ selected_pact.overall_latest?
38
+ )
17
39
  end
18
-
19
- non_pending_provider_tags = provider_version_tags - pending_provider_tags
20
-
21
- head_consumer_tags = head_pacts.collect(&:tag)
22
- overall_latest = head_consumer_tags.include?(nil)
23
- VerifiablePact.new(domain_pact,
24
- pending,
25
- pending_provider_tags,
26
- non_pending_provider_tags,
27
- head_consumer_tags.compact,
28
- overall_latest
29
- )
30
40
  end
31
41
 
32
42
  def squash_pacts_for_verification(*args)
@@ -6,13 +6,23 @@ module PactBroker
6
6
  READ_MORE_PENDING = "Read more at https://pact.io/pending"
7
7
  READ_MORE_WIP = "Read more at https://pact.io/wip"
8
8
 
9
- delegate [:consumer_name, :provider_name, :head_consumer_tags, :pending_provider_tags, :non_pending_provider_tags, :pending?, :wip?] => :verifiable_pact
9
+ delegate [:consumer_name, :provider_name, :consumer_version_number, :head_consumer_tags, :pending_provider_tags, :non_pending_provider_tags, :pending?, :wip?] => :verifiable_pact
10
10
 
11
11
  def initialize(verifiable_pact, pact_version_url)
12
12
  @verifiable_pact = verifiable_pact
13
13
  @pact_version_url = pact_version_url
14
14
  end
15
15
 
16
+ def pact_description
17
+ position_descs = if head_consumer_tags.empty?
18
+ ["latest"]
19
+ else
20
+ head_consumer_tags.collect { | tag | "latest #{tag}"}
21
+ end
22
+
23
+ "Pact between #{consumer_name} and #{provider_name}, consumer version #{consumer_version_number}, #{position_descs.join(",")}"
24
+ end
25
+
16
26
  def inclusion_reason
17
27
  version_text = head_consumer_tags.size == 1 ? "version" : "versions"
18
28
  if wip?
@@ -1,3 +1,3 @@
1
1
  module PactBroker
2
- VERSION = '2.46.0'
2
+ VERSION = '2.47.0'
3
3
  end
@@ -110,7 +110,8 @@ module PactBroker
110
110
  webhooks = webhook_repository.find_by_consumer_and_or_provider_and_event_name pact.consumer, pact.provider, event_name
111
111
 
112
112
  if webhooks.any?
113
- run_later(webhooks, pact, verification, event_name, options)
113
+ webhook_execution_configuration = options.fetch(:webhook_execution_configuration).with_webhook_context(event_name: event_name)
114
+ run_later(webhooks, pact, verification, event_name, options.merge(webhook_execution_configuration: webhook_execution_configuration))
114
115
  else
115
116
  logger.info "No enabled webhooks found for consumer \"#{pact.consumer.name}\" and provider \"#{pact.provider.name}\" and event #{event_name}"
116
117
  end
@@ -122,6 +123,7 @@ module PactBroker
122
123
  begin
123
124
  triggered_webhook = webhook_repository.create_triggered_webhook(trigger_uuid, webhook, pact, verification, RESOURCE_CREATION)
124
125
  logger.info "Scheduling job for webhook with uuid #{webhook.uuid}"
126
+ logger.debug "Schedule webhook with options #{options}"
125
127
  job_data = { triggered_webhook: triggered_webhook }.deep_merge(options)
126
128
  # Delay slightly to make sure the request transaction has finished before we execute the webhook
127
129
  Job.perform_in(5, job_data)
@@ -29,8 +29,9 @@ module PactBroker
29
29
  @options = options
30
30
  end
31
31
 
32
- def log(uuid, webhook_request, http_response, error)
32
+ def log(uuid, webhook_request, http_response, error, webhook_context)
33
33
  safe_response = http_response ? HttpResponseWithUtf8SafeBody.new(http_response) : nil
34
+ log_webhook_context(webhook_context)
34
35
  log_request(webhook_request)
35
36
  log_response(uuid, safe_response) if safe_response
36
37
  log_error(uuid, error) if error
@@ -42,6 +43,11 @@ module PactBroker
42
43
 
43
44
  attr_reader :log_stream
44
45
 
46
+ def log_webhook_context(webhook_context)
47
+ execution_logger.debug "Webhook context #{webhook_context.to_json}"
48
+ logger.debug("Webhook context #{webhook_context.to_json}")
49
+ end
50
+
45
51
  def log_request(webhook_request)
46
52
  http_request = HttpRequestWithRedactedHeaders.new(webhook_request.http_request)
47
53
  logger.info "Making webhook #{webhook_request.uuid} request #{http_request.method.upcase} URI=#{webhook_request.url} (headers and body in debug logs)"
data/pact_broker.gemspec CHANGED
@@ -74,7 +74,7 @@ Gem::Specification.new do |gem|
74
74
  gem.add_development_dependency 'webmock', '~>2.3'
75
75
  gem.add_development_dependency 'rspec', '~>3.0'
76
76
  gem.add_development_dependency 'rspec-its', '~>1.2'
77
- gem.add_development_dependency 'database_cleaner', '~>1.6'
77
+ gem.add_development_dependency 'database_cleaner', '~>1.8', '>= 1.8.1'
78
78
  gem.add_development_dependency 'pg', '~>0.21'
79
79
  gem.add_development_dependency 'conventional-changelog', '~>1.3'
80
80
  gem.add_development_dependency 'bump', '~> 0.5'
@@ -18,7 +18,7 @@ module PactBroker
18
18
  {
19
19
  provider_version_tags: ['master'],
20
20
  consumer_version_selectors: [ { tag: 'dev', latest: 'true' }],
21
- include_pending_status: false,
21
+ include_pending_status: 'true',
22
22
  include_wip_pacts_since: '2018-01-01'
23
23
  }
24
24
  end
@@ -32,7 +32,11 @@ module PactBroker
32
32
  "Bar",
33
33
  ["master"],
34
34
  [OpenStruct.new(tag: "dev", latest: true)],
35
- { include_wip_pacts_since: DateTime.parse('2018-01-01') })
35
+ {
36
+ include_wip_pacts_since: DateTime.parse('2018-01-01'),
37
+ include_pending_status: true
38
+ }
39
+ )
36
40
  subject
37
41
  end
38
42
 
@@ -54,8 +58,8 @@ module PactBroker
54
58
  {
55
59
  providerVersionTags: ['master'],
56
60
  consumerVersionSelectors: [ { tag: 'dev', latest: true }],
57
- includePendingStatus: false,
58
- includeWipPactsSince: '2018-01-01'
61
+ includePendingStatus: true,
62
+ includeWipPactsSince: '2018-01-01',
59
63
  }
60
64
  end
61
65
 
@@ -74,7 +78,11 @@ module PactBroker
74
78
  "Bar",
75
79
  ["master"],
76
80
  [OpenStruct.new(tag: "dev", latest: true)],
77
- { include_wip_pacts_since: DateTime.parse('2018-01-01') })
81
+ {
82
+ include_wip_pacts_since: DateTime.parse('2018-01-01'),
83
+ include_pending_status: true
84
+ }
85
+ )
78
86
  subject
79
87
  end
80
88
 
@@ -94,7 +102,7 @@ module PactBroker
94
102
  it "uses the correct options for the decorator" do
95
103
  expect(decorator).to receive(:to_json) do | options |
96
104
  expect(options[:user_options][:title]).to eq "Pacts to be verified by provider Bar"
97
- expect(options[:user_options][:include_pending_status]).to eq false
105
+ expect(options[:user_options][:include_pending_status]).to eq true
98
106
  end
99
107
  subject
100
108
  end
@@ -81,7 +81,7 @@ module PactBroker
81
81
  end
82
82
 
83
83
  it "generates the execution logs" do
84
- expect(webhook_request_logger).to receive(:log).with(uuid, webhook_request, http_response, nil)
84
+ expect(webhook_request_logger).to receive(:log).with(uuid, webhook_request, http_response, nil, webhook_context)
85
85
  execute
86
86
  end
87
87
 
@@ -106,7 +106,7 @@ module PactBroker
106
106
  end
107
107
 
108
108
  it "generates the execution logs" do
109
- expect(webhook_request_logger).to receive(:log).with(uuid, webhook_request, nil, instance_of(error_class))
109
+ expect(webhook_request_logger).to receive(:log).with(uuid, webhook_request, nil, instance_of(error_class), webhook_context)
110
110
  execute
111
111
  end
112
112
 
@@ -15,32 +15,48 @@ module PactBroker
15
15
  subject.find{ |pact| pact.consumer_name == consumer_name && pact.consumer_version_number == consumer_version_number }
16
16
  end
17
17
 
18
- before do
19
- td.create_pact_with_hierarchy("Foo", "foo-latest-prod-version", "Bar")
20
- .create_consumer_version_tag("prod")
21
- .create_consumer_version("not-latest-dev-version", tag_names: ["dev"])
22
- .comment("next pact not selected")
23
- .create_pact
24
- .create_consumer_version("foo-latest-dev-version", tag_names: ["dev"])
25
- .create_pact
26
- .create_consumer("Baz")
27
- .create_consumer_version("baz-latest-dev-version", tag_names: ["dev"])
28
- .create_pact
29
- end
30
18
 
31
19
  subject { Repository.new.find_for_verification("Bar", consumer_version_selectors) }
32
20
 
33
21
  context "when there are no selectors" do
22
+ before do
23
+ td.create_pact_with_hierarchy("Foo", "foo-latest-prod-version", "Bar")
24
+ .create_consumer_version_tag("prod")
25
+ .create_consumer_version("not-latest-dev-version", tag_names: ["dev"])
26
+ .comment("next pact not selected")
27
+ .create_pact
28
+ .create_consumer_version("foo-latest-dev-version", tag_names: ["dev"])
29
+ .create_pact
30
+ .create_consumer("Baz")
31
+ .create_consumer_version("baz-latest-dev-version", tag_names: ["dev"])
32
+ .create_pact
33
+ end
34
+
34
35
  let(:consumer_version_selectors) { [] }
35
36
 
36
37
  it "returns the latest pact for each consumer" do
37
38
  expect(subject.size).to eq 2
38
39
  expect(find_by_consumer_name_and_consumer_version_number("Foo", "foo-latest-dev-version")).to_not be nil
39
40
  expect(find_by_consumer_name_and_consumer_version_number("Baz", "baz-latest-dev-version")).to_not be nil
41
+ expect(subject.all?(&:overall_latest?)).to be true
40
42
  end
41
43
  end
42
44
 
43
- context "when consumer tag names are specified" do
45
+ context "when the latest consumer tag names are specified" do
46
+ before do
47
+ td.create_pact_with_hierarchy("Foo", "foo-latest-prod-version", "Bar")
48
+ .create_consumer_version_tag("prod")
49
+ .create_consumer_version("not-latest-dev-version", tag_names: ["dev"])
50
+ .comment("next pact not selected")
51
+ .create_pact
52
+ .create_consumer_version("foo-latest-dev-version", tag_names: ["dev"])
53
+ .create_pact
54
+ .create_consumer("Baz")
55
+ .create_consumer_version("baz-latest-dev-version", tag_names: ["dev"])
56
+ .create_consumer_version_tag("prod")
57
+ .create_pact
58
+ end
59
+
44
60
  let(:pact_selector_1) { double('selector', tag: 'dev', latest: true) }
45
61
  let(:pact_selector_2) { double('selector', tag: 'prod', latest: true) }
46
62
  let(:consumer_version_selectors) do
@@ -48,47 +64,78 @@ module PactBroker
48
64
  end
49
65
 
50
66
  it "returns the latest pact with the specified tags for each consumer" do
51
- expect(find_by_consumer_version_number("foo-latest-prod-version")).to_not be nil
52
- expect(find_by_consumer_version_number("foo-latest-dev-version")).to_not be nil
53
- expect(find_by_consumer_version_number("baz-latest-dev-version")).to_not be nil
67
+ expect(find_by_consumer_version_number("foo-latest-prod-version").selectors).to eq [Selector.latest_for_tag('prod')]
68
+ expect(find_by_consumer_version_number("foo-latest-dev-version").selectors).to eq [Selector.latest_for_tag('dev')]
69
+ expect(find_by_consumer_version_number("baz-latest-dev-version").selectors.sort_by{ |s| s[:tag] }).to eq [{ tag: 'dev', latest: true }, { tag: 'prod', latest: true }]
54
70
  expect(subject.size).to eq 3
55
71
  end
56
72
 
57
73
  it "sets the latest_consumer_version_tag_names" do
58
- expect(find_by_consumer_version_number("foo-latest-prod-version").tag).to eq 'prod'
74
+ expect(find_by_consumer_version_number("foo-latest-prod-version").selectors.collect(&:tag)).to eq ['prod']
75
+ end
76
+ end
77
+
78
+ context "when all versions with a given tag are requested" do
79
+ before do
80
+ td.create_pact_with_hierarchy("Foo2", "prod-version-1", "Bar2")
81
+ .create_consumer_version_tag("prod")
82
+ .create_consumer_version("not-prod-version", tag_names: %w[master])
83
+ .create_pact
84
+ .create_consumer_version("prod-version-2", tag_names: %w[prod])
85
+ .create_pact
86
+ end
87
+
88
+ let(:consumer_version_selectors) { [pact_selector_1] }
89
+ let(:pact_selector_1) { double('selector', tag: 'prod', latest: nil) }
90
+
91
+ subject { Repository.new.find_for_verification("Bar2", consumer_version_selectors) }
92
+
93
+ it "returns all the versions with the specified tag" do
94
+ expect(subject.size).to be 2
95
+ expect(find_by_consumer_version_number("prod-version-1").selectors.collect(&:tag)).to eq %w[prod]
96
+ expect(find_by_consumer_version_number("prod-version-2").selectors.collect(&:tag)).to eq %w[prod]
59
97
  end
60
98
 
61
- context "when all versions with a given tag are requested" do
62
- before do
63
- td.create_pact_with_hierarchy("Foo2", "prod-version-1", "Bar2")
64
- .create_consumer_version_tag("prod")
65
- .create_consumer_version("not-prod-version", tag_names: %w[master])
66
- .create_pact
67
- .create_consumer_version("prod-version-2", tag_names: %w[prod])
68
- .create_pact
69
- end
70
-
71
- let(:consumer_version_selectors) { [pact_selector_1] }
72
- let(:pact_selector_1) { double('selector', tag: 'prod', latest: nil) }
73
-
74
- subject { Repository.new.find_for_verification("Bar2", consumer_version_selectors) }
75
-
76
- it "returns all the versions with the specified tag" do
77
- expect(subject.size).to be 2
78
- expect(find_by_consumer_version_number("prod-version-1")).to_not be nil
79
- expect(find_by_consumer_version_number("prod-version-2")).to_not be nil
80
- end
81
-
82
- it "dedupes them to ensure that each pact version is only verified once" do
83
- td.create_consumer_version("prod-version-3", tag_names: %w[prod])
84
- .republish_same_pact
85
- expect(subject.size).to be 2
86
- expect(subject.collect(&:consumer_version_number)).to eq %w[prod-version-1 prod-version-3]
87
- end
99
+ it "dedupes them to ensure that each pact version is only verified once" do
100
+ td.create_consumer_version("prod-version-3", tag_names: %w[prod])
101
+ .republish_same_pact
102
+ expect(subject.size).to be 2
103
+ expect(subject.collect(&:consumer_version_number)).to eq %w[prod-version-1 prod-version-3]
104
+ end
105
+ end
106
+
107
+ context "when a pact version has been selected by two different selectors" do
108
+ before do
109
+ td.create_pact_with_hierarchy("Foo", "1", "Bar")
110
+ .create_consumer_version_tag("dev")
111
+ .create_consumer_version_tag("prod")
112
+ end
113
+
114
+ let(:consumer_version_selectors) { [pact_selector_1, pact_selector_2] }
115
+ let(:pact_selector_1) { double('selector1', tag: 'prod', latest: nil) }
116
+ let(:pact_selector_2) { double('selector2', tag: 'dev', latest: true) }
117
+ let(:consumer_version_selectors) { [pact_selector_1, pact_selector_2] }
118
+
119
+ it "returns a single selected pact with multiple selectors" do
120
+ expect(subject.size).to eq 1
121
+ expect(subject.first.selectors.size).to eq 2
88
122
  end
89
123
  end
90
124
 
91
125
  context "when no selectors are specified" do
126
+ before do
127
+ td.create_pact_with_hierarchy("Foo", "foo-latest-prod-version", "Bar")
128
+ .create_consumer_version_tag("prod")
129
+ .create_consumer_version("not-latest-dev-version", tag_names: ["dev"])
130
+ .comment("next pact not selected")
131
+ .create_pact
132
+ .create_consumer_version("foo-latest-dev-version", tag_names: ["dev"])
133
+ .create_pact
134
+ .create_consumer("Baz")
135
+ .create_consumer_version("baz-latest-dev-version", tag_names: ["dev"])
136
+ .create_pact
137
+ end
138
+
92
139
  let(:consumer_version_selectors) { [] }
93
140
 
94
141
  it "returns the latest pact for each provider" do
@@ -98,7 +145,7 @@ module PactBroker
98
145
  end
99
146
 
100
147
  it "does not set the tag name" do
101
- expect(find_by_consumer_version_number("foo-latest-dev-version").tag).to be nil
148
+ expect(find_by_consumer_version_number("foo-latest-dev-version").selectors).to eq [{ latest: true }]
102
149
  expect(find_by_consumer_version_number("foo-latest-dev-version").overall_latest?).to be true
103
150
  end
104
151
  end
@@ -4,7 +4,7 @@ module PactBroker
4
4
  module Pacts
5
5
  module SquashPactsForVerification
6
6
  describe ".call" do
7
- let(:head_pacts) { [pact_1, pact_2] }
7
+ let(:selected_pact) { pact_1 }
8
8
  let(:head_tag_1) { "dev" }
9
9
  let(:head_tag_2) { "feat-x" }
10
10
  let(:pact_version_sha_1) { "1" }
@@ -15,42 +15,23 @@ module PactBroker
15
15
  select_pending_provider_version_tags: pending_provider_version_tags
16
16
  )
17
17
  end
18
- let(:domain_pact_2) { double('pact2', pending?: pending_2) }
19
18
  let(:pending_1) { false }
20
- let(:pending_2) { false }
21
19
  let(:pending_provider_version_tags) { [] }
22
20
 
23
21
  let(:pact_1) do
24
- double("HeadPact",
25
- tag: head_tag_1,
26
- pact_version_sha: pact_version_sha_1,
27
- pact: domain_pact_1
22
+ double("SelectedPact",
23
+ tag_names_for_selectors_for_latest_pacts: %w[dev feat-x],
24
+ pact: domain_pact_1,
25
+ overall_latest?: false
28
26
  )
29
27
  end
30
28
 
31
- let(:pact_2) do
32
- double("HeadPact",
33
- tag: head_tag_2,
34
- pact_version_sha: pact_version_sha_2,
35
- pact: domain_pact_2
36
- )
37
- end
38
-
39
- let(:provider_name) { "Bar" }
40
29
  let(:provider_version_tags) { [] }
41
30
 
42
- subject { SquashPactsForVerification.call(provider_version_tags, head_pacts) }
31
+ subject { SquashPactsForVerification.call(provider_version_tags, selected_pact, true) }
43
32
 
44
- context "when all of the consumer tags are not nil" do
45
- its(:head_consumer_tags) { is_expected.to eq %w[dev feat-x] }
46
- its(:overall_latest?) { is_expected.to be false }
47
- end
48
-
49
- context "when one of the consumer tags is nil" do
50
- let(:head_tag_2) { nil }
51
- its(:head_consumer_tags) { is_expected.to eq %w[dev] }
52
- its(:overall_latest?) { is_expected.to be true }
53
- end
33
+ its(:head_consumer_tags) { is_expected.to eq %w[dev feat-x] }
34
+ its(:overall_latest?) { is_expected.to be false }
54
35
 
55
36
  context "when there are no provider tags" do
56
37
  context "when the pact version is not pending" do
@@ -13,6 +13,7 @@ module PactBroker
13
13
  double(VerifiablePact,
14
14
  head_consumer_tags: head_consumer_tags,
15
15
  consumer_name: "Foo",
16
+ consumer_version_number: "123",
16
17
  provider_name: "Bar",
17
18
  pending_provider_tags: pending_provider_tags,
18
19
  non_pending_provider_tags: non_pending_provider_tags,
@@ -32,6 +33,7 @@ module PactBroker
32
33
  context "when there is 1 head consumer tags" do
33
34
  let(:head_consumer_tags) { %w[dev] }
34
35
  its(:inclusion_reason) { is_expected.to include "The pact at http://pact is being verified because it is the pact for the latest version of Foo tagged with 'dev'" }
36
+ its(:pact_description) { is_expected.to eq "Pact between Foo and Bar, consumer version 123, latest dev"}
35
37
  end
36
38
 
37
39
  context "when there are 2 head consumer tags" do
@@ -152,14 +152,16 @@ module PactBroker
152
152
  let(:provider) { PactBroker::Domain::Pacticipant.new(name: 'Provider') }
153
153
  let(:webhooks) { [instance_double(PactBroker::Domain::Webhook, description: 'description', uuid: '1244')]}
154
154
  let(:triggered_webhook) { instance_double(PactBroker::Webhooks::TriggeredWebhook) }
155
+ let(:webhook_execution_configuration) { double('webhook_execution_configuration') }
155
156
  let(:options) do
156
157
  { database_connector: double('database_connector'),
157
- webhook_context: {},
158
+ webhook_execution_configuration: webhook_execution_configuration,
158
159
  logging_options: {}
159
160
  }
160
161
  end
161
162
 
162
163
  before do
164
+ allow(webhook_execution_configuration).to receive(:with_webhook_context).and_return(webhook_execution_configuration)
163
165
  allow_any_instance_of(PactBroker::Webhooks::Repository).to receive(:find_by_consumer_and_or_provider_and_event_name).and_return(webhooks)
164
166
  allow_any_instance_of(PactBroker::Webhooks::Repository).to receive(:create_triggered_webhook).and_return(triggered_webhook)
165
167
  allow(Job).to receive(:perform_in)
@@ -177,6 +179,11 @@ module PactBroker
177
179
  expect(Service).to receive(:run_later).with(webhooks, pact, verification, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, options)
178
180
  subject
179
181
  end
182
+
183
+ it "merges the event name in the options" do
184
+ expect(webhook_execution_configuration).to receive(:with_webhook_context).with(event_name: PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED)
185
+ subject
186
+ end
180
187
  end
181
188
 
182
189
  context "when no webhooks are found" do
@@ -50,9 +50,11 @@ module PactBroker
50
50
  }
51
51
  end
52
52
 
53
+ let(:webhook_context) { { consumer_version_number: "123" } }
54
+
53
55
  let(:webhook_request_logger) { WebhookRequestLogger.new(options) }
54
56
 
55
- subject(:logs) { webhook_request_logger.log(uuid, webhook_request, response, error) }
57
+ subject(:logs) { webhook_request_logger.log(uuid, webhook_request, response, error, webhook_context) }
56
58
 
57
59
  describe "application logs" do
58
60
  it "logs the request" do
@@ -69,6 +71,9 @@ module PactBroker
69
71
  end
70
72
 
71
73
  describe "execution logs" do
74
+ it "logs the application context" do
75
+ expect(logs).to include webhook_context.to_json
76
+ end
72
77
 
73
78
  it "logs the request method and path" do
74
79
  expect(logs).to include "POST http://example.org/hook"
@@ -11,10 +11,12 @@ if __FILE__ == $0
11
11
  def webrick_opts port
12
12
  certificate = OpenSSL::X509::Certificate.new(File.read(SSL_CERT))
13
13
  cert_name = certificate.subject.to_a.collect{|a| a[0..1] }
14
+ logger_stream = ENV['DEBUG'] ? $stderr : StringIO.new
14
15
  {
15
16
  Port: port,
16
17
  Host: "0.0.0.0",
17
18
  AccessLog: [],
19
+ Logger: WEBrick::Log.new(logger_stream,WEBrick::Log::INFO),
18
20
  SSLCertificate: certificate,
19
21
  SSLPrivateKey: OpenSSL::PKey::RSA.new(File.read(SSL_KEY)),
20
22
  SSLEnable: true,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pact_broker
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.46.0
4
+ version: 2.47.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bethany Skurrie
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-01-30 00:00:00.000000000 Z
13
+ date: 2020-02-01 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: httparty
@@ -480,14 +480,20 @@ dependencies:
480
480
  requirements:
481
481
  - - "~>"
482
482
  - !ruby/object:Gem::Version
483
- version: '1.6'
483
+ version: '1.8'
484
+ - - ">="
485
+ - !ruby/object:Gem::Version
486
+ version: 1.8.1
484
487
  type: :development
485
488
  prerelease: false
486
489
  version_requirements: !ruby/object:Gem::Requirement
487
490
  requirements:
488
491
  - - "~>"
489
492
  - !ruby/object:Gem::Version
490
- version: '1.6'
493
+ version: '1.8'
494
+ - - ">="
495
+ - !ruby/object:Gem::Version
496
+ version: 1.8.1
491
497
  - !ruby/object:Gem::Dependency
492
498
  name: pg
493
499
  requirement: !ruby/object:Gem::Requirement
@@ -1051,6 +1057,8 @@ files:
1051
1057
  - lib/pact_broker/pacts/parse.rb
1052
1058
  - lib/pact_broker/pacts/placeholder_pact.rb
1053
1059
  - lib/pact_broker/pacts/repository.rb
1060
+ - lib/pact_broker/pacts/selected_pact.rb
1061
+ - lib/pact_broker/pacts/selector.rb
1054
1062
  - lib/pact_broker/pacts/service.rb
1055
1063
  - lib/pact_broker/pacts/sort_content.rb
1056
1064
  - lib/pact_broker/pacts/squash_pacts_for_verification.rb
@@ -1604,7 +1612,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1604
1612
  - !ruby/object:Gem::Version
1605
1613
  version: '0'
1606
1614
  requirements: []
1607
- rubygems_version: 3.1.2
1615
+ rubyforge_project:
1616
+ rubygems_version: 2.7.6
1608
1617
  signing_key:
1609
1618
  specification_version: 4
1610
1619
  summary: See description