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 +4 -4
- data/CHANGELOG.md +9 -0
- data/Dockerfile +1 -0
- data/lib/pact_broker/api/resources/provider_pacts_for_verification.rb +4 -1
- data/lib/pact_broker/api/resources/verification.rb +2 -2
- data/lib/pact_broker/api/resources/verifications.rb +1 -1
- data/lib/pact_broker/domain/webhook.rb +5 -4
- data/lib/pact_broker/pacts/repository.rb +59 -14
- data/lib/pact_broker/pacts/selected_pact.rb +46 -0
- data/lib/pact_broker/pacts/selector.rb +43 -0
- data/lib/pact_broker/pacts/service.rb +2 -4
- data/lib/pact_broker/pacts/squash_pacts_for_verification.rb +30 -20
- data/lib/pact_broker/pacts/verifiable_pact_messages.rb +11 -1
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/webhooks/service.rb +3 -1
- data/lib/pact_broker/webhooks/webhook_request_logger.rb +7 -1
- data/pact_broker.gemspec +1 -1
- data/spec/lib/pact_broker/api/resources/provider_pacts_for_verification_spec.rb +14 -6
- data/spec/lib/pact_broker/domain/webhook_spec.rb +2 -2
- data/spec/lib/pact_broker/pacts/repository_find_for_verification_spec.rb +92 -45
- data/spec/lib/pact_broker/pacts/squash_pacts_for_verification_spec.rb +8 -27
- data/spec/lib/pact_broker/pacts/verifiable_pact_messages_spec.rb +2 -0
- data/spec/lib/pact_broker/webhooks/service_spec.rb +8 -1
- data/spec/lib/pact_broker/webhooks/webhook_request_logger_spec.rb +6 -1
- data/spec/support/ssl_webhook_server.rb +2 -0
- metadata +14 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c54fb8ff19038af9dd5d0a09105244459a18febe23333bf5203ef77424eb97a3
|
4
|
+
data.tar.gz: f380f9f5e9939d9844e88f09b5807a5e1f094cc368adfa22c104ee8ad55d9f97
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ebfc52497d4d877c0adb715bd1bf39c1be9513893ffaf032e142d160b4aa12be04c5b01d0c698f7b94ea6aadca1a416cddd53e3a0f304bb9c2821d128cf894a2
|
7
|
+
data.tar.gz: 41184e2249f9bde504a6f9258bf44ff2f33a8374d6a2d05ebe59536c8113461c79f41319a9b337f1db58c83e31ff652951ffca7466988626150dab7e09002abb
|
data/CHANGELOG.md
CHANGED
data/Dockerfile
CHANGED
@@ -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
|
-
{
|
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
|
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
|
148
|
-
|
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
|
-
|
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
|
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.
|
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
|
-
|
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.
|
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
|
-
|
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
|
-
.
|
122
|
-
|
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,
|
9
|
-
domain_pact =
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
pending =
|
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
|
-
|
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?
|
data/lib/pact_broker/version.rb
CHANGED
@@ -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
|
-
|
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.
|
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:
|
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
|
-
{
|
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:
|
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
|
-
{
|
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
|
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")).
|
52
|
-
expect(find_by_consumer_version_number("foo-latest-dev-version")).
|
53
|
-
expect(find_by_consumer_version_number("baz-latest-dev-version")).
|
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
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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").
|
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(:
|
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("
|
25
|
-
|
26
|
-
|
27
|
-
|
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,
|
31
|
+
subject { SquashPactsForVerification.call(provider_version_tags, selected_pact, true) }
|
43
32
|
|
44
|
-
|
45
|
-
|
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
|
-
|
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.
|
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
|
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.
|
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.
|
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
|
-
|
1615
|
+
rubyforge_project:
|
1616
|
+
rubygems_version: 2.7.6
|
1608
1617
|
signing_key:
|
1609
1618
|
specification_version: 4
|
1610
1619
|
summary: See description
|