pact_broker 2.66.0 → 2.67.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 +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
|