pact_broker 2.66.0 → 2.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/Gemfile +1 -0
- data/db/migrations/20201006_add_wip_to_verification.rb +5 -0
- data/lib/db.rb +3 -1
- data/lib/pact_broker/api/decorators/verifiable_pact_decorator.rb +4 -2
- data/lib/pact_broker/api/pact_broker_urls.rb +10 -6
- data/lib/pact_broker/api/paths.rb +4 -3
- data/lib/pact_broker/api/resources/can_i_deploy.rb +14 -0
- data/lib/pact_broker/api/resources/group.rb +0 -1
- data/lib/pact_broker/api/resources/latest_pact.rb +1 -1
- data/lib/pact_broker/api/resources/pact.rb +8 -0
- data/lib/pact_broker/api/resources/pact_versions.rb +4 -0
- data/lib/pact_broker/api/resources/pact_webhooks.rb +1 -1
- data/lib/pact_broker/api/resources/provider_pacts_for_verification.rb +1 -2
- data/lib/pact_broker/api/resources/tag.rb +0 -1
- data/lib/pact_broker/api/resources/tagged_pact_versions.rb +4 -0
- data/lib/pact_broker/api/resources/verification.rb +4 -0
- data/lib/pact_broker/api/resources/verifications.rb +14 -2
- data/lib/pact_broker/groups/service.rb +0 -3
- data/lib/pact_broker/locale/en.yml +1 -0
- data/lib/pact_broker/matrix/aggregated_row.rb +1 -0
- data/lib/pact_broker/matrix/query_results_with_deployment_status_summary.rb +1 -0
- data/lib/pact_broker/pacts/all_pact_publications.rb +1 -0
- data/lib/pact_broker/pacts/pact_publication.rb +1 -0
- data/lib/pact_broker/pacts/repository.rb +1 -0
- data/lib/pact_broker/pacts/verifiable_pact_messages.rb +2 -0
- data/lib/pact_broker/test/test_data_builder.rb +1 -1
- data/lib/pact_broker/verifications/service.rb +2 -1
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/webhooks/pact_and_verification_parameters.rb +1 -1
- data/spec/features/create_webhook_spec.rb +18 -0
- data/spec/features/wip_pacts_spec.rb +258 -33
- data/spec/fixtures/approvals/modifiable_resources.approved.json +74 -0
- data/spec/lib/pact_broker/api/decorators/relationships_csv_decorator_spec.rb +0 -3
- data/spec/lib/pact_broker/api/decorators/verifiable_pact_decorator_spec.rb +7 -2
- data/spec/lib/pact_broker/api/pact_broker_urls_spec.rb +6 -5
- data/spec/lib/pact_broker/api/resources/can_i_deploy_spec.rb +51 -0
- data/spec/lib/pact_broker/api/resources/default_base_resource_approval_spec.rb +59 -0
- data/spec/lib/pact_broker/api/resources/latest_pact_spec.rb +2 -2
- data/spec/lib/pact_broker/api/resources/verifications_spec.rb +17 -3
- data/spec/lib/pact_broker/pacts/latest_tagged_pact_publications_spec.rb +1 -1
- data/spec/lib/pact_broker/pacts/repository_find_wip_pact_versions_for_provider_spec.rb +24 -2
- data/spec/lib/pact_broker/verifications/service_spec.rb +4 -2
- data/spec/lib/pact_broker/webhooks/render_spec.rb +1 -1
- data/spec/spec_helper.rb +5 -0
- metadata +9 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2874fe6ca6f552e6cba4d848f56998d0473d860ec4aa47530ccf883d9f189cfe
|
|
4
|
+
data.tar.gz: b8e28ffebc86a0f28251489edb9cd92407a4f2758e4fdc519f1d47d7c32cbf2d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f6bae75159d6ed6b50e0c96f71cd0931d52b94e6fb251d21e31153d67ce892dfaecdf64932f0bca27f06418fb61c67b9348129a5f662590c528d401a2a2df27d
|
|
7
|
+
data.tar.gz: 31b4370cd7d1e4c9b4b7825f013a58c327a1b3766f62ce59380bd878160dde2725cee60a2401625772b88378cb258ca8d5ebfa927131cdaf66ac1636352e4cda
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
<a name="v2.67.0"></a>
|
|
2
|
+
### v2.67.0 (2020-10-16)
|
|
3
|
+
|
|
4
|
+
#### Features
|
|
5
|
+
|
|
6
|
+
* **wip pacts**
|
|
7
|
+
* if a pact was successfully verified because it was included as a WIP pact, keep it as WIP ([16cae55d](/../../commit/16cae55d))
|
|
8
|
+
* add 'wip' column to verification results ([34f98592](/../../commit/34f98592))
|
|
9
|
+
|
|
10
|
+
#### Bug Fixes
|
|
11
|
+
|
|
12
|
+
* typo when rendering created webhook for old webhooks path ([1e6a06a0](/../../commit/1e6a06a0))
|
|
13
|
+
* include can-i-deploy badge in is_badge_path? logic ([31ea5f34](/../../commit/31ea5f34))
|
|
14
|
+
|
|
15
|
+
* **pacts for verification**
|
|
16
|
+
* gracefully log empty request body ([0e48d13a](/../../commit/0e48d13a))
|
|
17
|
+
|
|
18
|
+
* **can-i-deploy**
|
|
19
|
+
* gracefully handle pacticipant not found ([f6903b23](/../../commit/f6903b23))
|
|
20
|
+
|
|
1
21
|
<a name="v2.66.0"></a>
|
|
2
22
|
### v2.66.0 (2020-10-01)
|
|
3
23
|
|
data/Gemfile
CHANGED
data/lib/db.rb
CHANGED
|
@@ -27,7 +27,9 @@ module DB
|
|
|
27
27
|
def self.connect db_credentials
|
|
28
28
|
# Keep this conifiguration in sync with lib/pact_broker/app.rb#configure_database_connection
|
|
29
29
|
Sequel.datetime_class = DateTime
|
|
30
|
-
|
|
30
|
+
if ENV['DEBUG'] == 'true'
|
|
31
|
+
logger = Logger.new($stdout)
|
|
32
|
+
end
|
|
31
33
|
con = Sequel.connect(db_credentials.merge(:logger => logger, :pool_class => Sequel::ThreadedConnectionPool, :encoding => 'utf8'))
|
|
32
34
|
con.extension(:connection_validator)
|
|
33
35
|
con.extension(:pagination)
|
|
@@ -20,14 +20,16 @@ module PactBroker
|
|
|
20
20
|
getter: -> (context) { context[:decorator].notices(context[:options][:user_options]) }
|
|
21
21
|
|
|
22
22
|
def notices(user_options)
|
|
23
|
-
|
|
23
|
+
metadata = represented.wip ? { wip: true } : nil
|
|
24
|
+
pact_url = pact_version_url_with_metadata(represented, metadata, user_options[:base_url])
|
|
24
25
|
PactBroker::Pacts::BuildVerifiablePactNotices.call(represented, pact_url, user_options)
|
|
25
26
|
end
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
link :self do | user_options |
|
|
30
|
+
metadata = represented.wip ? { wip: true } : nil
|
|
29
31
|
{
|
|
30
|
-
href:
|
|
32
|
+
href: pact_version_url_with_metadata(represented, metadata, user_options[:base_url]),
|
|
31
33
|
name: represented.name
|
|
32
34
|
}
|
|
33
35
|
end
|
|
@@ -58,19 +58,23 @@ module PactBroker
|
|
|
58
58
|
"#{pactigration_base_url(base_url, pact)}/pact-version/#{pact.pact_version_sha}"
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
def pact_version_url_with_metadata pact, base_url = ''
|
|
62
|
-
|
|
61
|
+
def pact_version_url_with_metadata pact, metadata, base_url = ''
|
|
62
|
+
if metadata && metadata.any?
|
|
63
|
+
"#{pact_version_url(pact, base_url)}/metadata/#{encode_metadata(metadata)}"
|
|
64
|
+
else
|
|
65
|
+
pact_version_url(pact, base_url)
|
|
66
|
+
end
|
|
63
67
|
end
|
|
64
68
|
|
|
65
|
-
def
|
|
66
|
-
|
|
69
|
+
def pact_version_url_with_webhook_metadata pact, base_url = ''
|
|
70
|
+
pact_version_url_with_metadata(pact, build_metadata_for_webhook_triggered_by_pact_publication(pact), base_url)
|
|
67
71
|
end
|
|
68
72
|
|
|
69
|
-
def
|
|
73
|
+
def encode_metadata(metadata)
|
|
70
74
|
Base64.strict_encode64(Rack::Utils.build_nested_query(metadata))
|
|
71
75
|
end
|
|
72
76
|
|
|
73
|
-
def
|
|
77
|
+
def decode_pact_metadata(metadata)
|
|
74
78
|
if metadata
|
|
75
79
|
begin
|
|
76
80
|
Rack::Utils.parse_nested_query(Base64.strict_decode64(metadata)).each_with_object({}) do | (k, v), new_hash |
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
module PactBroker
|
|
2
2
|
module Api
|
|
3
3
|
module Paths
|
|
4
|
-
PACT_BADGE_PATH =
|
|
5
|
-
MATRIX_BADGE_PATH =
|
|
4
|
+
PACT_BADGE_PATH = %r{^/pacts/provider/[^/]+/consumer/.*/badge(?:\.[A-Za-z]+)?$}.freeze
|
|
5
|
+
MATRIX_BADGE_PATH = %r{^/matrix/provider/[^/]+/latest/[^/]+/consumer/[^/]+/latest/[^/]+/badge(?:\.[A-Za-z]+)?$}.freeze
|
|
6
|
+
CAN_I_DEPLOY_BADGE_PATH = %r{^/pacticipants/[^/]+/latest-version/[^/]+/can-i-deploy/to/[^/]+/badge(?:\.[A-Za-z]+)?$}.freeze
|
|
6
7
|
|
|
7
8
|
extend self
|
|
8
9
|
|
|
9
10
|
def is_badge_path?(path)
|
|
10
11
|
# Optimise by checking include? first - regexp slow
|
|
11
|
-
path.include?('/badge') && (path =~ PACT_BADGE_PATH || path =~ MATRIX_BADGE_PATH)
|
|
12
|
+
path.include?('/badge') && (path =~ PACT_BADGE_PATH || path =~ MATRIX_BADGE_PATH || path =~ CAN_I_DEPLOY_BADGE_PATH)
|
|
12
13
|
end
|
|
13
14
|
end
|
|
14
15
|
end
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
require 'pact_broker/api/resources/matrix'
|
|
2
2
|
require 'pact_broker/matrix/can_i_deploy_query_schema'
|
|
3
3
|
require 'pact_broker/matrix/parse_can_i_deploy_query'
|
|
4
|
+
require 'pact_broker/messages'
|
|
4
5
|
|
|
5
6
|
module PactBroker
|
|
6
7
|
module Api
|
|
7
8
|
module Resources
|
|
8
9
|
class CanIDeploy < Matrix
|
|
10
|
+
include PactBroker::Messages
|
|
11
|
+
|
|
9
12
|
def initialize
|
|
10
13
|
super
|
|
11
14
|
@query_params = JSON.parse(Rack::Utils.parse_nested_query(request.uri.query).to_json, symbolize_names: true)
|
|
@@ -16,6 +19,9 @@ module PactBroker
|
|
|
16
19
|
if (errors = query_schema.call(query_params)).any?
|
|
17
20
|
set_json_validation_error_messages(errors)
|
|
18
21
|
true
|
|
22
|
+
elsif !pacticipant
|
|
23
|
+
set_json_validation_error_messages(pacticipant: [message('errors.validation.pacticipant_not_found', name: pacticipant_name)])
|
|
24
|
+
true
|
|
19
25
|
else
|
|
20
26
|
false
|
|
21
27
|
end
|
|
@@ -32,6 +38,14 @@ module PactBroker
|
|
|
32
38
|
def query_schema
|
|
33
39
|
PactBroker::Api::Contracts::CanIDeployQuerySchema
|
|
34
40
|
end
|
|
41
|
+
|
|
42
|
+
def pacticipant
|
|
43
|
+
@pacticipant ||= pacticipant_service.find_pacticipant_by_name(pacticipant_name)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def pacticipant_name
|
|
47
|
+
selectors.first.pacticipant_name
|
|
48
|
+
end
|
|
35
49
|
end
|
|
36
50
|
end
|
|
37
51
|
end
|
|
@@ -50,7 +50,7 @@ module PactBroker
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def metadata
|
|
53
|
-
@metadata ||=
|
|
53
|
+
@metadata ||= encode_metadata(PactBroker::Pacts::Metadata.build_metadata_for_latest_pact(pact, identifier_from_path))
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
end
|
|
@@ -52,7 +52,7 @@ module PactBroker
|
|
|
52
52
|
|
|
53
53
|
def from_json
|
|
54
54
|
saved_webhook = webhook_service.create next_uuid, webhook, consumer, provider
|
|
55
|
-
response.body = Decorators::WebhookDecorator.new(saved_webhook).to_json(
|
|
55
|
+
response.body = Decorators::WebhookDecorator.new(saved_webhook).to_json(decorator_options)
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
def to_json
|
|
@@ -85,8 +85,7 @@ module PactBroker
|
|
|
85
85
|
end
|
|
86
86
|
|
|
87
87
|
def log_request
|
|
88
|
-
|
|
89
|
-
logger.info "Fetching pacts for verification by #{provider_name}", provider_name: provider_name, params: parameters
|
|
88
|
+
logger.info "Fetching pacts for verification by #{provider_name}", provider_name: provider_name, params: query
|
|
90
89
|
end
|
|
91
90
|
|
|
92
91
|
def nested_query
|
|
@@ -48,7 +48,7 @@ module PactBroker
|
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
def from_json
|
|
51
|
-
verification = verification_service.create(next_verification_number,
|
|
51
|
+
verification = verification_service.create(next_verification_number, verification_params, pact, webhook_options)
|
|
52
52
|
response.body = decorator_for(verification).to_json(decorator_options)
|
|
53
53
|
true
|
|
54
54
|
end
|
|
@@ -57,6 +57,10 @@ module PactBroker
|
|
|
57
57
|
:'verifications::verifications'
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
+
def policy_pacticipant
|
|
61
|
+
provider
|
|
62
|
+
end
|
|
63
|
+
|
|
60
64
|
private
|
|
61
65
|
|
|
62
66
|
def pact
|
|
@@ -72,7 +76,11 @@ module PactBroker
|
|
|
72
76
|
end
|
|
73
77
|
|
|
74
78
|
def metadata
|
|
75
|
-
PactBrokerUrls.
|
|
79
|
+
PactBrokerUrls.decode_pact_metadata(identifier_from_path[:metadata])
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def wip?
|
|
83
|
+
metadata[:wip] == 'true'
|
|
76
84
|
end
|
|
77
85
|
|
|
78
86
|
def webhook_options
|
|
@@ -82,6 +90,10 @@ module PactBroker
|
|
|
82
90
|
.with_webhook_context(metadata)
|
|
83
91
|
}
|
|
84
92
|
end
|
|
93
|
+
|
|
94
|
+
def verification_params
|
|
95
|
+
params(symbolize_names: false).merge('wip' => wip?)
|
|
96
|
+
end
|
|
85
97
|
end
|
|
86
98
|
end
|
|
87
99
|
end
|
|
@@ -45,6 +45,7 @@ en:
|
|
|
45
45
|
pacticipant_name_mismatch: "in pact ('%{name_in_pact}') does not match %{pacticipant} name in path ('%{name}')."
|
|
46
46
|
connection_encoding_not_utf8: "The Sequel connection encoding (%{encoding}) is strongly recommended to be \"utf8\". If you need to set it to %{encoding} for some particular reason, then disable this check by setting config.validate_database_connection_config = false"
|
|
47
47
|
invalid_webhook_uuid: The UUID can only contain the characters A-Z, a-z, 0-9, _ and -, and must be 16 or more characters.
|
|
48
|
+
pacticipant_not_found: No pacticipant with name '%{name}' found
|
|
48
49
|
duplicate_pacticipant: |
|
|
49
50
|
This is the first time a pact has been published for "%{new_name}".
|
|
50
51
|
The name "%{new_name}" is very similar to the following existing consumers/providers:
|
|
@@ -316,7 +316,7 @@ module PactBroker
|
|
|
316
316
|
parameters.delete(:comment)
|
|
317
317
|
tag_names = [parameters.delete(:tag_names), parameters.delete(:tag_name)].flatten.compact
|
|
318
318
|
provider_version_number = parameters[:provider_version] || '4.5.6'
|
|
319
|
-
default_parameters = {success: true, number: 1, test_results: {some: 'results'}}
|
|
319
|
+
default_parameters = { success: true, number: 1, test_results: {some: 'results'}, wip: false }
|
|
320
320
|
default_parameters[:execution_date] = @now if @now
|
|
321
321
|
parameters = default_parameters.merge(parameters)
|
|
322
322
|
parameters.delete(:provider_version)
|
|
@@ -21,10 +21,11 @@ module PactBroker
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def create next_verification_number, params, pact, webhook_options
|
|
24
|
-
logger.info "Creating verification #{next_verification_number} for pact_id=#{pact.id}
|
|
24
|
+
logger.info "Creating verification #{next_verification_number} for pact_id=#{pact.id}", payload: params.reject{ |k,_| k == "testResults"}
|
|
25
25
|
verification = PactBroker::Domain::Verification.new
|
|
26
26
|
provider_version_number = params.fetch('providerApplicationVersion')
|
|
27
27
|
PactBroker::Api::Decorators::VerificationDecorator.new(verification).from_hash(params)
|
|
28
|
+
verification.wip = params.fetch('wip')
|
|
28
29
|
verification.number = next_verification_number
|
|
29
30
|
verification = verification_repository.create(verification, provider_version_number, pact)
|
|
30
31
|
|
data/lib/pact_broker/version.rb
CHANGED
|
@@ -38,7 +38,7 @@ module PactBroker
|
|
|
38
38
|
|
|
39
39
|
def to_hash
|
|
40
40
|
@hash ||= {
|
|
41
|
-
PACT_URL => pact ? PactBroker::Api::PactBrokerUrls.
|
|
41
|
+
PACT_URL => pact ? PactBroker::Api::PactBrokerUrls.pact_version_url_with_webhook_metadata(pact, base_url) : "",
|
|
42
42
|
VERIFICATION_RESULT_URL => verification_url,
|
|
43
43
|
CONSUMER_VERSION_NUMBER => consumer_version_number,
|
|
44
44
|
PROVIDER_VERSION_NUMBER => verification ? verification.provider_version_number : "",
|
|
@@ -123,4 +123,22 @@ describe "Creating a webhook" do
|
|
|
123
123
|
expect(PactBroker::Webhooks::Webhook.first.provider).to_not be nil
|
|
124
124
|
end
|
|
125
125
|
end
|
|
126
|
+
|
|
127
|
+
context "with the old path" do
|
|
128
|
+
let(:path) { "/pacts/provider/Some%20Provider/consumer/Some%20Consumer/webhooks" }
|
|
129
|
+
|
|
130
|
+
its(:status) { is_expected.to be 201 }
|
|
131
|
+
|
|
132
|
+
it "returns the Location header" do
|
|
133
|
+
expect(subject.headers['Location']).to match(%r{http://example.org/webhooks/.+})
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "returns a JSON Content Type" do
|
|
137
|
+
expect(subject.headers['Content-Type']).to eq 'application/hal+json;charset=utf-8'
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "returns the newly created webhook" do
|
|
141
|
+
expect(response_body).to include webhook_hash
|
|
142
|
+
end
|
|
143
|
+
end
|
|
126
144
|
end
|
|
@@ -1,26 +1,9 @@
|
|
|
1
1
|
RSpec.describe "the lifecycle of a WIP pact" do
|
|
2
|
-
before do
|
|
3
|
-
td.set_now(DateTime.now - 100)
|
|
4
|
-
.create_provider("Bar")
|
|
5
|
-
.create_provider_version("1")
|
|
6
|
-
.create_provider_version_tag("master")
|
|
7
|
-
end
|
|
8
2
|
let(:pact_content_1) { { interactions: [{ some: 'interaction'}] }.to_json }
|
|
9
3
|
let(:pact_content_2) { { interactions: [{ some: 'other interaction'}] }.to_json }
|
|
4
|
+
let(:pact_content_3) { { interactions: [{ some: 'other other interaction'}] }.to_json }
|
|
10
5
|
let(:request_headers) { { "CONTENT_TYPE" => "application/json", "HTTP_ACCEPT" => "application/hal+json"} }
|
|
11
6
|
let(:provider_version_number) { "2" }
|
|
12
|
-
let(:failed_verification_results) do
|
|
13
|
-
{
|
|
14
|
-
providerApplicationVersion: provider_version_number,
|
|
15
|
-
success: false
|
|
16
|
-
}.to_json
|
|
17
|
-
end
|
|
18
|
-
let(:successful_verification_results) do
|
|
19
|
-
{
|
|
20
|
-
providerApplicationVersion: provider_version_number,
|
|
21
|
-
success: true
|
|
22
|
-
}.to_json
|
|
23
|
-
end
|
|
24
7
|
let(:pacts_for_verification_request_body) do
|
|
25
8
|
{
|
|
26
9
|
consumerVersionSelectors: [ { tag: "master", latest: true } ],
|
|
@@ -28,20 +11,48 @@ RSpec.describe "the lifecycle of a WIP pact" do
|
|
|
28
11
|
includeWipPactsSince: start_date
|
|
29
12
|
}.to_json
|
|
30
13
|
end
|
|
14
|
+
|
|
31
15
|
let(:start_date) { (Date.today - 1).to_datetime }
|
|
32
16
|
|
|
17
|
+
def create_initial_provider_version_on_master
|
|
18
|
+
td.set_now(DateTime.now - 100)
|
|
19
|
+
.create_provider("Bar")
|
|
20
|
+
.create_provider_version("1")
|
|
21
|
+
.create_provider_version_tag("master")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def can_i_merge(consumer_version)
|
|
25
|
+
can_i_deploy(consumer_version, "master")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def can_i_deploy(consumer_version, provider_tag)
|
|
29
|
+
can_i_deploy_response = get("/can-i-deploy", { pacticipant: "Foo", version: consumer_version, to: provider_tag })
|
|
30
|
+
JSON.parse(can_i_deploy_response.body)["summary"]["deployable"]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
33
|
def publish_pact_with_master_tag
|
|
34
34
|
put("/pacts/provider/Bar/consumer/Foo/version/1", pact_content_1, request_headers)
|
|
35
35
|
put("/pacticipants/Foo/versions/1/tags/master", nil, request_headers)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
def publish_pact_with_feature_tag
|
|
39
|
-
put("/pacts/provider/Bar/consumer/Foo/version
|
|
40
|
-
put("/pacticipants/Foo/versions/
|
|
38
|
+
def publish_pact_with_feature_tag(version = "2", tag = "feat-x", pact_content = nil)
|
|
39
|
+
put("/pacts/provider/Bar/consumer/Foo/version/#{version}", pact_content || pact_content_2, request_headers)
|
|
40
|
+
put("/pacticipants/Foo/versions/#{version}/tags/#{tag}", nil, request_headers)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def publish_new_pact_with_master_tag_after_merging_in_feature_branch
|
|
44
|
+
put("/pacts/provider/Bar/consumer/Foo/version/3", pact_content_2, request_headers)
|
|
45
|
+
put("/pacticipants/Foo/versions/2/tags/master", nil, request_headers)
|
|
41
46
|
end
|
|
42
47
|
|
|
43
|
-
def get_pacts_for_verification
|
|
44
|
-
post("/pacts/provider/Bar/for-verification", pacts_for_verification_request_body, request_headers)
|
|
48
|
+
def get_pacts_for_verification(request_body = nil)
|
|
49
|
+
post("/pacts/provider/Bar/for-verification", request_body || pacts_for_verification_request_body, request_headers)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def pact_urls_from(pacts_for_verification_response)
|
|
53
|
+
JSON.parse(pacts_for_verification_response.body)["_embedded"]["pacts"].collect do | pact |
|
|
54
|
+
pact["_links"]["self"]["href"]
|
|
55
|
+
end
|
|
45
56
|
end
|
|
46
57
|
|
|
47
58
|
def wip_pact_url_from(pacts_for_verification_response)
|
|
@@ -49,16 +60,21 @@ RSpec.describe "the lifecycle of a WIP pact" do
|
|
|
49
60
|
end
|
|
50
61
|
|
|
51
62
|
def get_pact(pact_url)
|
|
52
|
-
get
|
|
63
|
+
get(pact_url, nil, request_headers)
|
|
53
64
|
end
|
|
54
65
|
|
|
55
66
|
def verification_results_url_from(pact_response)
|
|
56
67
|
JSON.parse(pact_response.body)["_links"]["pb:publish-verification-results"]["href"]
|
|
57
68
|
end
|
|
58
69
|
|
|
59
|
-
def publish_verification_results_with_tag_master(verification_results_url,
|
|
60
|
-
|
|
61
|
-
|
|
70
|
+
def publish_verification_results_with_tag_master(verification_results_url, success)
|
|
71
|
+
publish_verification_results(provider_version_number, "master", verification_results_url, success)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def publish_verification_results(provider_version_number, tag, verification_results_url, success)
|
|
75
|
+
request_body = { success: success, providerApplicationVersion: provider_version_number}.to_json
|
|
76
|
+
post(verification_results_url, request_body, request_headers)
|
|
77
|
+
put("/pacticipants/Bar/versions/#{provider_version_number}/tags/#{tag}", nil, request_headers)
|
|
62
78
|
end
|
|
63
79
|
|
|
64
80
|
def pending_status_from(pacts_for_verification_response)
|
|
@@ -71,10 +87,20 @@ RSpec.describe "the lifecycle of a WIP pact" do
|
|
|
71
87
|
end
|
|
72
88
|
end
|
|
73
89
|
|
|
90
|
+
def build_pacts_for_verification_request_body(provider_version_tag, consumer_version_tag = nil)
|
|
91
|
+
{
|
|
92
|
+
consumerVersionSelectors: [ { tag: consumer_version_tag || provider_version_tag, latest: true, fallbackTag: "master" } ],
|
|
93
|
+
providerVersionTags: [provider_version_tag],
|
|
94
|
+
includeWipPactsSince: start_date
|
|
95
|
+
}.to_json
|
|
96
|
+
end
|
|
97
|
+
|
|
74
98
|
context "when the includeWipPactsSince date is specified" do
|
|
75
99
|
context "a pact published afer the specified date, with a tag that is not specified explictly in the 'pacts for verification' request" do
|
|
76
100
|
describe "when it is first published" do
|
|
77
101
|
it "is included in the list of pacts to verify as a WIP pact" do
|
|
102
|
+
create_initial_provider_version_on_master
|
|
103
|
+
|
|
78
104
|
publish_pact_with_master_tag
|
|
79
105
|
publish_pact_with_feature_tag
|
|
80
106
|
|
|
@@ -85,6 +111,8 @@ RSpec.describe "the lifecycle of a WIP pact" do
|
|
|
85
111
|
|
|
86
112
|
describe "when it is verified unsuccessfully" do
|
|
87
113
|
it "is still included as a WIP pact" do
|
|
114
|
+
create_initial_provider_version_on_master
|
|
115
|
+
|
|
88
116
|
# CONSUMER BUILD
|
|
89
117
|
# publish pact
|
|
90
118
|
publish_pact_with_master_tag
|
|
@@ -100,7 +128,7 @@ RSpec.describe "the lifecycle of a WIP pact" do
|
|
|
100
128
|
|
|
101
129
|
# publish failure verification results
|
|
102
130
|
verification_results_url = verification_results_url_from(pact_response)
|
|
103
|
-
publish_verification_results_with_tag_master(verification_results_url,
|
|
131
|
+
publish_verification_results_with_tag_master(verification_results_url, false)
|
|
104
132
|
|
|
105
133
|
# ANOTHER PROVIDER BUILD
|
|
106
134
|
# get pacts for verification
|
|
@@ -110,8 +138,10 @@ RSpec.describe "the lifecycle of a WIP pact" do
|
|
|
110
138
|
end
|
|
111
139
|
end
|
|
112
140
|
|
|
113
|
-
describe "when it is verified successfully" do
|
|
114
|
-
it "is
|
|
141
|
+
describe "when it is verified successfully while included as a WIP pact" do
|
|
142
|
+
it "is still included as a WIP pact" do
|
|
143
|
+
create_initial_provider_version_on_master
|
|
144
|
+
|
|
115
145
|
# CONSUMER BUILD
|
|
116
146
|
publish_pact_with_master_tag
|
|
117
147
|
publish_pact_with_feature_tag
|
|
@@ -124,18 +154,213 @@ RSpec.describe "the lifecycle of a WIP pact" do
|
|
|
124
154
|
|
|
125
155
|
# verify pact... success!
|
|
126
156
|
|
|
127
|
-
# publish
|
|
157
|
+
# publish success verification results
|
|
128
158
|
verification_results_url = verification_results_url_from(pact_response)
|
|
129
|
-
publish_verification_results_with_tag_master(verification_results_url,
|
|
159
|
+
publish_verification_results_with_tag_master(verification_results_url, true)
|
|
130
160
|
|
|
131
161
|
# ANOTHER PROVIDER BUILD 2
|
|
132
162
|
# get pacts for verification
|
|
133
163
|
# publish successful verification results
|
|
134
164
|
pacts_for_verification_response = get_pacts_for_verification
|
|
135
|
-
#
|
|
165
|
+
# still wip
|
|
166
|
+
expect(wip_pacts_from(pacts_for_verification_response).size).to eq 1
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
describe "when it is verified successfully when included explicitly" do
|
|
171
|
+
it "is no longer included as a WIP pact" do
|
|
172
|
+
create_initial_provider_version_on_master
|
|
173
|
+
|
|
174
|
+
# CONSUMER BUILD
|
|
175
|
+
publish_pact_with_master_tag
|
|
176
|
+
publish_pact_with_feature_tag
|
|
177
|
+
|
|
178
|
+
# PROVIDER BUILD
|
|
179
|
+
# fetch pacts to verify
|
|
180
|
+
pacts_for_verification_response = get_pacts_for_verification
|
|
181
|
+
pact_url = wip_pact_url_from(pacts_for_verification_response)
|
|
182
|
+
pact_response = get_pact(pact_url)
|
|
183
|
+
|
|
184
|
+
# verify pact... success!
|
|
185
|
+
|
|
186
|
+
# publish success verification results
|
|
187
|
+
verification_results_url = verification_results_url_from(pact_response)
|
|
188
|
+
publish_verification_results_with_tag_master(verification_results_url, true)
|
|
189
|
+
|
|
190
|
+
# CONSUMER BUILD
|
|
191
|
+
# merge feature branch into master
|
|
192
|
+
publish_new_pact_with_master_tag_after_merging_in_feature_branch
|
|
193
|
+
|
|
194
|
+
# ANOTHER PROVIDER BUILD 3
|
|
195
|
+
# get pacts for verification
|
|
196
|
+
# publish successful verification results
|
|
197
|
+
pacts_for_verification_response = get_pacts_for_verification
|
|
198
|
+
# no longer wip
|
|
199
|
+
expect(wip_pacts_from(pacts_for_verification_response).size).to eq 0
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
describe "a feature branching scenario" do
|
|
204
|
+
it "keeps being WIP until the branch is merged" do
|
|
205
|
+
create_initial_provider_version_on_master
|
|
206
|
+
|
|
207
|
+
# CONSUMER BUILD - master
|
|
208
|
+
publish_pact_with_master_tag
|
|
209
|
+
|
|
210
|
+
# CONSUMER BUILD - feature branch
|
|
211
|
+
publish_pact_with_feature_tag
|
|
212
|
+
expect(can_i_merge("2")).to_not be true
|
|
213
|
+
|
|
214
|
+
# PROVIDER BUILD
|
|
215
|
+
# fetch pacts to verify
|
|
216
|
+
pacts_for_verification_response = get_pacts_for_verification
|
|
217
|
+
pact_url = wip_pact_url_from(pacts_for_verification_response)
|
|
218
|
+
pact_response = get_pact(pact_url)
|
|
219
|
+
|
|
220
|
+
# verify pact... success!
|
|
221
|
+
|
|
222
|
+
# publish success verification results
|
|
223
|
+
verification_results_url = verification_results_url_from(pact_response)
|
|
224
|
+
publish_verification_results("1", "master", verification_results_url, true)
|
|
225
|
+
|
|
226
|
+
# CONSUMER
|
|
227
|
+
expect(can_i_merge("2")).to be true
|
|
228
|
+
|
|
229
|
+
# ANOTHER PROVIDER BUILD before the consumer build runs again
|
|
230
|
+
# fetch pacts to verify
|
|
231
|
+
pacts_for_verification_response = get_pacts_for_verification
|
|
232
|
+
# feat-x pact is still wip
|
|
233
|
+
pact_url = wip_pact_url_from(pacts_for_verification_response)
|
|
234
|
+
pact_response = get_pact(pact_url)
|
|
235
|
+
|
|
236
|
+
# however feat-x pact is no longer pending because it has a successful verification from master!!!
|
|
237
|
+
# Question: do we want this behaviour? Or should pending use the same logic?
|
|
238
|
+
expect(wip_pacts_from(pacts_for_verification_response).first['verificationProperties']['wip']).to be true
|
|
239
|
+
expect(wip_pacts_from(pacts_for_verification_response).first['verificationProperties']['pending']).to be nil
|
|
240
|
+
|
|
241
|
+
# verify pact... success!
|
|
242
|
+
|
|
243
|
+
# publish success verification results
|
|
244
|
+
verification_results_url = verification_results_url_from(pact_response)
|
|
245
|
+
publish_verification_results("2", "master", verification_results_url, true)
|
|
246
|
+
|
|
247
|
+
# CONSUMER BUILD
|
|
248
|
+
# merge feature branch into master
|
|
249
|
+
expect(can_i_merge("2")).to be true
|
|
250
|
+
publish_new_pact_with_master_tag_after_merging_in_feature_branch
|
|
251
|
+
expect(can_i_deploy("3", "master")).to be true
|
|
252
|
+
|
|
253
|
+
# ANOTHER PROVIDER BUILD 3
|
|
254
|
+
# get pacts for verification
|
|
255
|
+
# publish successful verification results
|
|
256
|
+
pacts_for_verification_response = get_pacts_for_verification
|
|
257
|
+
# no longer wip
|
|
136
258
|
expect(wip_pacts_from(pacts_for_verification_response).size).to eq 0
|
|
137
259
|
end
|
|
138
260
|
end
|
|
261
|
+
|
|
262
|
+
describe "a feature branching scenario with matching feature branches" do
|
|
263
|
+
it "stays wip on master even after it has been successfully verified on the provider's feature branch" do
|
|
264
|
+
create_initial_provider_version_on_master
|
|
265
|
+
|
|
266
|
+
# CONSUMER BUILD - master
|
|
267
|
+
publish_pact_with_master_tag
|
|
268
|
+
|
|
269
|
+
# CONSUMER BUILD - feature branch
|
|
270
|
+
publish_pact_with_feature_tag
|
|
271
|
+
|
|
272
|
+
# PROVIDER BUILD - master
|
|
273
|
+
# fetch pacts to verify
|
|
274
|
+
pacts_for_verification_response = get_pacts_for_verification(build_pacts_for_verification_request_body("master"))
|
|
275
|
+
pact_url = wip_pact_url_from(pacts_for_verification_response)
|
|
276
|
+
pact_response = get_pact(pact_url)
|
|
277
|
+
|
|
278
|
+
# verify pact... failure (not implemented on master yet)
|
|
279
|
+
|
|
280
|
+
# publish failure verification results
|
|
281
|
+
verification_results_url = verification_results_url_from(pact_response)
|
|
282
|
+
publish_verification_results("1", "master", verification_results_url, false)
|
|
283
|
+
|
|
284
|
+
# PROVIDER BUILD - on a matching feature branch
|
|
285
|
+
# fetch pacts to verify
|
|
286
|
+
pacts_for_verification_response = get_pacts_for_verification(build_pacts_for_verification_request_body("feat-x"))
|
|
287
|
+
# pact is not WIP because it has been explicitly included
|
|
288
|
+
expect(wip_pacts_from(pacts_for_verification_response).size).to eq 0
|
|
289
|
+
pact_url = pact_urls_from(pacts_for_verification_response).first
|
|
290
|
+
pact_response = get_pact(pact_url)
|
|
291
|
+
|
|
292
|
+
# verify pact - success on feature branch!
|
|
293
|
+
|
|
294
|
+
# publish successful results from feature branch
|
|
295
|
+
verification_results_url = verification_results_url_from(pact_response)
|
|
296
|
+
publish_verification_results("2", "feat-x", verification_results_url, true)
|
|
297
|
+
|
|
298
|
+
# PROVIDER BUILD - back on master
|
|
299
|
+
pacts_for_verification_response = get_pacts_for_verification(build_pacts_for_verification_request_body("master"))
|
|
300
|
+
# still wip for master
|
|
301
|
+
expect(wip_pacts_from(pacts_for_verification_response).size).to eq 1
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
describe "when a brand new provider branch is created" do
|
|
306
|
+
it "does not include any previously created WIP pacts because every single pact is pending for this new branch, and we don't want to verify the world" do
|
|
307
|
+
create_initial_provider_version_on_master
|
|
308
|
+
|
|
309
|
+
# CONSUMER BUILD - master
|
|
310
|
+
publish_pact_with_master_tag
|
|
311
|
+
|
|
312
|
+
# CONSUMER BUILD - feature branch
|
|
313
|
+
publish_pact_with_feature_tag
|
|
314
|
+
|
|
315
|
+
# PROVIDER BUILD - brand new feature branch
|
|
316
|
+
pacts_for_verification_response = get_pacts_for_verification(build_pacts_for_verification_request_body("feat-y", "master"))
|
|
317
|
+
expect(wip_pacts_from(pacts_for_verification_response).size).to eq 0
|
|
318
|
+
|
|
319
|
+
# verify master pact successfully
|
|
320
|
+
pact_url = pact_urls_from(pacts_for_verification_response).first
|
|
321
|
+
pact_response = get_pact(pact_url)
|
|
322
|
+
|
|
323
|
+
# publish successful results from feature branch
|
|
324
|
+
verification_results_url = verification_results_url_from(pact_response)
|
|
325
|
+
publish_verification_results("2", "feat-y", verification_results_url, true)
|
|
326
|
+
|
|
327
|
+
# PROVIDER BUILD 2 - feature branch
|
|
328
|
+
pacts_for_verification_response = get_pacts_for_verification(build_pacts_for_verification_request_body("feat-y", "master"))
|
|
329
|
+
# still no wip pacts
|
|
330
|
+
expect(wip_pacts_from(pacts_for_verification_response).size).to eq 0
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
it "does include any subsequently created new pacts" do
|
|
334
|
+
create_initial_provider_version_on_master
|
|
335
|
+
|
|
336
|
+
# CONSUMER BUILD - master
|
|
337
|
+
publish_pact_with_master_tag
|
|
338
|
+
|
|
339
|
+
# CONSUMER BUILD - feature branch
|
|
340
|
+
publish_pact_with_feature_tag
|
|
341
|
+
|
|
342
|
+
# PROVIDER BUILD - brand new feature branch
|
|
343
|
+
pacts_for_verification_response = get_pacts_for_verification(build_pacts_for_verification_request_body("feat-y", "master"))
|
|
344
|
+
expect(wip_pacts_from(pacts_for_verification_response).size).to eq 0
|
|
345
|
+
# verify master pact successfully (creates a new provider version with tag feat-y)
|
|
346
|
+
pact_url = pact_urls_from(pacts_for_verification_response).first
|
|
347
|
+
pact_response = get_pact(pact_url)
|
|
348
|
+
verification_results_url = verification_results_url_from(pact_response)
|
|
349
|
+
publish_verification_results("2", "feat-y", verification_results_url, true)
|
|
350
|
+
sleep 1 if ::DB.mysql? # time resolution is lower on MySQL, need to make sure the next pacts are created after the above provider version
|
|
351
|
+
|
|
352
|
+
# CONSUMER BUILD - feature branch again
|
|
353
|
+
# republish same pact content with new version
|
|
354
|
+
publish_pact_with_feature_tag("3")
|
|
355
|
+
|
|
356
|
+
# CONSUMER BUILD - another feature branch
|
|
357
|
+
publish_pact_with_feature_tag("4", "feat-z", pact_content_3)
|
|
358
|
+
|
|
359
|
+
# PROVIDER BUILD - brand new feature branch again
|
|
360
|
+
pacts_for_verification_response = get_pacts_for_verification(build_pacts_for_verification_request_body("feat-y", "master"))
|
|
361
|
+
expect(wip_pacts_from(pacts_for_verification_response).size).to eq 2
|
|
362
|
+
end
|
|
363
|
+
end
|
|
139
364
|
end
|
|
140
365
|
end
|
|
141
366
|
end
|