pact_broker 2.8.0.beta.5 → 2.9.0.beta.5
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 +13 -0
- data/lib/pact_broker/app.rb +2 -0
- data/lib/pact_broker/configuration.rb +4 -0
- data/lib/pact_broker/domain/webhook.rb +2 -2
- data/lib/pact_broker/domain/webhook_request.rb +31 -17
- data/lib/pact_broker/matrix/parse_query.rb +6 -0
- data/lib/pact_broker/matrix/repository.rb +77 -51
- data/lib/pact_broker/matrix/row.rb +41 -1
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/webhooks/triggered_webhook.rb +1 -1
- data/lib/rack/pact_broker/store_base_url.rb +14 -0
- data/script/seed.rb +1 -1
- data/script/webhook-server.ru +5 -1
- data/spec/features/execute_webhook_spec.rb +8 -3
- data/spec/lib/pact_broker/domain/webhook_request_spec.rb +65 -15
- data/spec/lib/pact_broker/domain/webhook_spec.rb +5 -3
- data/spec/lib/pact_broker/matrix/repository_spec.rb +133 -0
- data/spec/service_consumers/provider_states_for_pact_broker_client.rb +11 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf490a74cabeccee8ad6973db3e32c96a0ff2f6b
|
4
|
+
data.tar.gz: a4983395d117314b3c7da784a7855a20d5483147
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9720bb92c02c741b93c63b127c4c53fab0bbf980fc7af1842fce100186fc78edfd8936ef2c535dc6c51c1d2aeff4057b48c4a2c3f4e568243456e285a6604476
|
7
|
+
data.tar.gz: 67f17b7730351717e5c47b87b7813065c1eac0d02750c9908fbe5264acb75ddc38e659197766b5de85599949805e324924a0467e427fd4f60f99ce654d3d8498
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
<a name="v2.9.0.beta.5"></a>
|
2
|
+
### v2.9.0.beta.5 (2017-11-09)
|
3
|
+
|
4
|
+
|
5
|
+
#### Features
|
6
|
+
|
7
|
+
* **webhook templating**
|
8
|
+
* add support for ${pactbroker.pactUrl} in query and body ([0eed596](/../../commit/0eed596))
|
9
|
+
|
10
|
+
* **matrix**
|
11
|
+
* allow query to determine if a particular pacticipant version is compatible with the latest tagged versions of all its dependencies ([ba4a1cc](/../../commit/ba4a1cc))
|
12
|
+
|
13
|
+
|
1
14
|
<a name="v2.8.0.beta.5"></a>
|
2
15
|
### v2.8.0.beta.5 (2017-11-06)
|
3
16
|
|
data/lib/pact_broker/app.rb
CHANGED
@@ -3,6 +3,7 @@ require 'pact_broker/db'
|
|
3
3
|
require 'pact_broker/project_root'
|
4
4
|
require 'rack-protection'
|
5
5
|
require 'rack/hal_browser'
|
6
|
+
require 'rack/pact_broker/store_base_url'
|
6
7
|
require 'rack/pact_broker/add_pact_broker_version_header'
|
7
8
|
require 'rack/pact_broker/convert_file_extension_to_accept_header'
|
8
9
|
require 'rack/pact_broker/database_transaction'
|
@@ -106,6 +107,7 @@ module PactBroker
|
|
106
107
|
# NOTE THAT NONE OF THIS IS PROTECTED BY AUTH - is that ok?
|
107
108
|
@app_builder.use Rack::Protection, except: [:path_traversal, :remote_token, :session_hijacking, :http_origin]
|
108
109
|
@app_builder.use Rack::PactBroker::InvalidUriProtection
|
110
|
+
@app_builder.use Rack::PactBroker::StoreBaseURL
|
109
111
|
@app_builder.use Rack::PactBroker::AddPactBrokerVersionHeader
|
110
112
|
@app_builder.use Rack::Static, :urls => ["/stylesheets", "/css", "/fonts", "/js", "/javascripts", "/images"], :root => PactBroker.project_root.join("public")
|
111
113
|
@app_builder.use Rack::Static, :urls => ["/favicon.ico"], :root => PactBroker.project_root.join("public/images"), header_rules: [[:all, {'Content-Type' => 'image/x-icon'}]]
|
@@ -123,6 +123,10 @@ module PactBroker
|
|
123
123
|
self.enable_public_badge_access = enable_badge_resources
|
124
124
|
end
|
125
125
|
|
126
|
+
def base_url
|
127
|
+
ENV['PACT_BROKER_BASE_URL']
|
128
|
+
end
|
129
|
+
|
126
130
|
def save_to_database
|
127
131
|
# Can't require a Sequel::Model class before the connection has been set
|
128
132
|
require 'pact_broker/config/save'
|
@@ -4,6 +4,7 @@ require 'pact_broker/logging'
|
|
4
4
|
require 'pact_broker/messages'
|
5
5
|
require 'net/http'
|
6
6
|
require 'pact_broker/webhooks/redact_logs'
|
7
|
+
require 'pact_broker/api/pact_broker_urls'
|
7
8
|
|
8
9
|
module PactBroker
|
9
10
|
|
@@ -47,11 +48,11 @@ module PactBroker
|
|
47
48
|
password.nil? ? nil : "**********"
|
48
49
|
end
|
49
50
|
|
50
|
-
def execute options = {}
|
51
|
+
def execute pact, options = {}
|
51
52
|
logs = StringIO.new
|
52
53
|
execution_logger = Logger.new(logs)
|
53
54
|
begin
|
54
|
-
execute_and_build_result(options, logs, execution_logger)
|
55
|
+
execute_and_build_result(pact, options, logs, execution_logger)
|
55
56
|
rescue StandardError => e
|
56
57
|
handle_error_and_build_result(e, options, logs, execution_logger)
|
57
58
|
end
|
@@ -59,9 +60,10 @@ module PactBroker
|
|
59
60
|
|
60
61
|
private
|
61
62
|
|
62
|
-
def execute_and_build_result options, logs, execution_logger
|
63
|
-
|
64
|
-
|
63
|
+
def execute_and_build_result pact, options, logs, execution_logger
|
64
|
+
uri = build_uri(pact)
|
65
|
+
req = build_request(uri, pact, execution_logger)
|
66
|
+
response = do_request(uri, req)
|
65
67
|
log_response(response, execution_logger)
|
66
68
|
result = WebhookExecutionResult.new(response, logs.string)
|
67
69
|
log_completion_message(options, execution_logger, result.success?)
|
@@ -75,9 +77,9 @@ module PactBroker
|
|
75
77
|
WebhookExecutionResult.new(nil, logs.string, e)
|
76
78
|
end
|
77
79
|
|
78
|
-
def build_request execution_logger
|
79
|
-
req = http_request
|
80
|
-
execution_logger.info "HTTP/1.1 #{method.upcase} #{url_with_credentials}"
|
80
|
+
def build_request uri, pact, execution_logger
|
81
|
+
req = http_request(uri)
|
82
|
+
execution_logger.info "HTTP/1.1 #{method.upcase} #{url_with_credentials(pact)}"
|
81
83
|
|
82
84
|
headers.each_pair do | name, value |
|
83
85
|
execution_logger.info Webhooks::RedactLogs.call("#{name}: #{value}")
|
@@ -88,9 +90,9 @@ module PactBroker
|
|
88
90
|
|
89
91
|
unless body.nil?
|
90
92
|
if String === body
|
91
|
-
req.body = body
|
93
|
+
req.body = gsub_body(pact, body)
|
92
94
|
else
|
93
|
-
req.body = body.to_json
|
95
|
+
req.body = gsub_body(pact, body.to_json)
|
94
96
|
end
|
95
97
|
end
|
96
98
|
|
@@ -98,7 +100,7 @@ module PactBroker
|
|
98
100
|
req
|
99
101
|
end
|
100
102
|
|
101
|
-
def do_request req
|
103
|
+
def do_request uri, req
|
102
104
|
logger.info "Making webhook #{uuid} request #{to_s}"
|
103
105
|
Net::HTTP.start(uri.hostname, uri.port,
|
104
106
|
:use_ssl => uri.scheme == 'https') do |http|
|
@@ -126,19 +128,31 @@ module PactBroker
|
|
126
128
|
"#{method.upcase} #{url}, username=#{username}, password=#{display_password}, headers=#{headers}, body=#{body}"
|
127
129
|
end
|
128
130
|
|
129
|
-
def http_request
|
130
|
-
Net::HTTP.const_get(method.capitalize).new(
|
131
|
+
def http_request(uri)
|
132
|
+
Net::HTTP.const_get(method.capitalize).new(uri)
|
131
133
|
end
|
132
134
|
|
133
|
-
def
|
134
|
-
URI(url)
|
135
|
+
def build_uri pact
|
136
|
+
URI(gsub_url(pact, url))
|
135
137
|
end
|
136
138
|
|
137
|
-
def url_with_credentials
|
138
|
-
u =
|
139
|
+
def url_with_credentials pact
|
140
|
+
u = build_uri(pact)
|
139
141
|
u.userinfo = "#{username}:#{display_password}" if username
|
140
142
|
u
|
141
143
|
end
|
144
|
+
|
145
|
+
def gsub_body pact, body
|
146
|
+
base_url = PactBroker.configuration.base_url
|
147
|
+
body.gsub('${pactbroker.pactUrl}', PactBroker::Api::PactBrokerUrls.pact_url(base_url, pact))
|
148
|
+
end
|
149
|
+
|
150
|
+
def gsub_url pact, url
|
151
|
+
base_url = PactBroker.configuration.base_url
|
152
|
+
pact_url = PactBroker::Api::PactBrokerUrls.pact_url(base_url, pact)
|
153
|
+
escaped_pact_url = CGI::escape(pact_url)
|
154
|
+
url.gsub('${pactbroker.pactUrl}', escaped_pact_url)
|
155
|
+
end
|
142
156
|
end
|
143
157
|
end
|
144
158
|
end
|
@@ -31,6 +31,12 @@ module PactBroker
|
|
31
31
|
if params.key?('limit')
|
32
32
|
options[:limit] = params['limit']
|
33
33
|
end
|
34
|
+
if params.key?('latest')
|
35
|
+
options[:latest] = params['latest']
|
36
|
+
end
|
37
|
+
if params.key?('tag')
|
38
|
+
options[:tag] = params['tag']
|
39
|
+
end
|
34
40
|
return selectors, options
|
35
41
|
end
|
36
42
|
end
|
@@ -18,8 +18,8 @@ module PactBroker
|
|
18
18
|
def find selectors, options = {}
|
19
19
|
# The group with the nil provider_version_numbers will be the results of the left outer join
|
20
20
|
# that don't have verifications, so we need to include them all.
|
21
|
-
lines =
|
22
|
-
lines =
|
21
|
+
lines = query_matrix(resolve_selectors(selectors, options), options)
|
22
|
+
lines = apply_latestby(options, selectors, lines)
|
23
23
|
|
24
24
|
if options.key?(:success)
|
25
25
|
lines = lines.select{ |l| options[:success].include?(l.success) }
|
@@ -28,11 +28,7 @@ module PactBroker
|
|
28
28
|
lines.sort.collect(&:values)
|
29
29
|
end
|
30
30
|
|
31
|
-
def
|
32
|
-
selectors.all?{ |s| s[:pacticipant_version_number] }
|
33
|
-
end
|
34
|
-
|
35
|
-
def apply_scope options, selectors, lines
|
31
|
+
def apply_latestby options, selectors, lines
|
36
32
|
return lines unless options[:latestby] == 'cvp' || options[:latestby] == 'cp'
|
37
33
|
|
38
34
|
group_by_columns = case options[:latestby]
|
@@ -48,46 +44,41 @@ module PactBroker
|
|
48
44
|
|
49
45
|
def find_for_consumer_and_provider pacticipant_1_name, pacticipant_2_name
|
50
46
|
selectors = [{ pacticipant_name: pacticipant_1_name }, { pacticipant_name: pacticipant_2_name }]
|
51
|
-
|
47
|
+
options = { latestby: 'cvpv' }
|
48
|
+
query_matrix(resolve_selectors(selectors, options), options).sort.collect(&:values)
|
52
49
|
end
|
53
50
|
|
54
51
|
def find_compatible_pacticipant_versions selectors
|
55
52
|
find(selectors, latestby: 'cvpv').select{|line| line[:success] }
|
56
53
|
end
|
57
54
|
|
58
|
-
|
59
|
-
|
60
|
-
#
|
61
|
-
def find_all selectors, options
|
62
|
-
selectors = look_up_versions_for_tags(selectors)
|
63
|
-
query = base_table(options).select_all
|
64
|
-
|
65
|
-
if selectors.size == 1
|
66
|
-
query = where_consumer_or_provider_is(selectors.first, query)
|
67
|
-
else
|
68
|
-
query = where_consumer_and_provider_in(selectors, query)
|
69
|
-
end
|
70
|
-
|
55
|
+
def query_matrix selectors, options
|
56
|
+
query = view_for(options).select_all.matching_selectors(selectors)
|
71
57
|
query = query.limit(options[:limit]) if options[:limit]
|
72
|
-
query.
|
73
|
-
Sequel.asc(:consumer_name),
|
74
|
-
Sequel.desc(:consumer_version_order),
|
75
|
-
Sequel.desc(:pact_revision_number),
|
76
|
-
Sequel.asc(:provider_name),
|
77
|
-
Sequel.desc(:provider_version_order),
|
78
|
-
Sequel.desc(:verification_id)).all
|
58
|
+
query.order_by_names_ascending_most_recent_first.all
|
79
59
|
end
|
80
60
|
|
81
|
-
def
|
82
|
-
|
83
|
-
return LatestRow
|
61
|
+
def view_for(options)
|
62
|
+
options[:latestby] ? LatestRow : Row
|
84
63
|
end
|
85
64
|
|
86
|
-
def
|
65
|
+
def resolve_selectors(selectors, options)
|
66
|
+
selectors = look_up_versions_for_latest_and_tag(selectors, options)
|
67
|
+
|
68
|
+
if options[:latest]
|
69
|
+
apply_latest_and_tag_to_inferred_selectors(selectors, options)
|
70
|
+
else
|
71
|
+
selectors
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Find the version number for selectors with the latest (tagged) version specified
|
76
|
+
def look_up_versions_for_latest_and_tag(selectors, options)
|
87
77
|
selectors.collect do | selector |
|
88
78
|
# resource validation currently stops tag being specified without latest=true
|
89
79
|
if selector[:tag] && selector[:latest]
|
90
80
|
version = version_repository.find_by_pacticpant_name_and_latest_tag(selector[:pacticipant_name], selector[:tag])
|
81
|
+
raise "Could not find version with tag #{selector[:tag].inspect} for #{selector[:pacticipant_name]}" unless version
|
91
82
|
# validation in resource should ensure we always have a version
|
92
83
|
{
|
93
84
|
pacticipant_name: selector[:pacticipant_name],
|
@@ -105,28 +96,63 @@ module PactBroker
|
|
105
96
|
end
|
106
97
|
end
|
107
98
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
}
|
99
|
+
# eg. when checking to see if Foo version 2 can be deployed to prod,
|
100
|
+
# need to look up all the 'partner' pacticipants, and determine their latest prod versions
|
101
|
+
def apply_latest_and_tag_to_inferred_selectors(selectors, options)
|
102
|
+
all_pacticipant_names = all_pacticipant_names_in_specified_matrix(selectors, options)
|
103
|
+
specified_names = selectors.collect{ |s| s[:pacticipant_name] }
|
104
|
+
inferred_names = all_pacticipant_names - specified_names
|
105
|
+
|
106
|
+
inferred_selectors = inferred_names.collect do | pacticipant_name |
|
107
|
+
{
|
108
|
+
pacticipant_name: pacticipant_name,
|
109
|
+
latest: options[:latest]
|
110
|
+
}.tap { |it| it[:tag] = options[:tag] if options[:tag] }
|
111
|
+
end
|
112
|
+
|
113
|
+
selectors + look_up_versions_for_latest_and_tag(inferred_selectors, options)
|
120
114
|
end
|
121
115
|
|
122
|
-
def
|
123
|
-
query.
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
116
|
+
def all_pacticipant_names_in_specified_matrix(selectors, options)
|
117
|
+
query = view_for(options).select(:consumer_name, :provider_name)
|
118
|
+
query = query.matching_selectors(selectors)
|
119
|
+
query
|
120
|
+
.all
|
121
|
+
.collect{ | row | [row.consumer_name, row.provider_name] }
|
122
|
+
.flatten
|
123
|
+
.uniq
|
129
124
|
end
|
125
|
+
|
126
|
+
# def where_row_matches_selectors selectors, query
|
127
|
+
# if selectors.size == 1
|
128
|
+
# where_consumer_or_provider_is(selectors.first, query)
|
129
|
+
# else
|
130
|
+
# where_consumer_and_provider_in(selectors, query)
|
131
|
+
# end
|
132
|
+
# end
|
133
|
+
|
134
|
+
# def where_consumer_and_provider_in selectors, query
|
135
|
+
# query.where{
|
136
|
+
# Sequel.&(
|
137
|
+
# Sequel.|(
|
138
|
+
# *selectors.collect{ |s| s[:pacticipant_version_number] ? Sequel.&(consumer_name: s[:pacticipant_name], consumer_version_number: s[:pacticipant_version_number]) : Sequel.&(consumer_name: s[:pacticipant_name]) }
|
139
|
+
# ),
|
140
|
+
# Sequel.|(
|
141
|
+
# *(selectors.collect{ |s| s[:pacticipant_version_number] ? Sequel.&(provider_name: s[:pacticipant_name], provider_version_number: s[:pacticipant_version_number]) : Sequel.&(provider_name: s[:pacticipant_name]) } +
|
142
|
+
# selectors.collect{ |s| Sequel.&(provider_name: s[:pacticipant_name], provider_version_number: nil) })
|
143
|
+
# )
|
144
|
+
# )
|
145
|
+
# }
|
146
|
+
# end
|
147
|
+
|
148
|
+
# def where_consumer_or_provider_is s, query
|
149
|
+
# query.where{
|
150
|
+
# Sequel.|(
|
151
|
+
# s[:pacticipant_version_number] ? Sequel.&(consumer_name: s[:pacticipant_name], consumer_version_number: s[:pacticipant_version_number]) : Sequel.&(consumer_name: s[:pacticipant_name]),
|
152
|
+
# s[:pacticipant_version_number] ? Sequel.&(provider_name: s[:pacticipant_name], provider_version_number: s[:pacticipant_version_number]) : Sequel.&(provider_name: s[:pacticipant_name])
|
153
|
+
# )
|
154
|
+
# }
|
155
|
+
# end
|
130
156
|
end
|
131
157
|
end
|
132
158
|
end
|
@@ -6,6 +6,47 @@ module PactBroker
|
|
6
6
|
|
7
7
|
dataset_module do
|
8
8
|
include PactBroker::Repositories::Helpers
|
9
|
+
|
10
|
+
def matching_selectors selectors
|
11
|
+
if selectors.size == 1
|
12
|
+
where_consumer_or_provider_is(selectors.first)
|
13
|
+
else
|
14
|
+
where_consumer_and_provider_in(selectors)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def where_consumer_and_provider_in selectors
|
19
|
+
where{
|
20
|
+
Sequel.&(
|
21
|
+
Sequel.|(
|
22
|
+
*selectors.collect{ |s| s[:pacticipant_version_number] ? Sequel.&(consumer_name: s[:pacticipant_name], consumer_version_number: s[:pacticipant_version_number]) : Sequel.&(consumer_name: s[:pacticipant_name]) }
|
23
|
+
),
|
24
|
+
Sequel.|(
|
25
|
+
*(selectors.collect{ |s| s[:pacticipant_version_number] ? Sequel.&(provider_name: s[:pacticipant_name], provider_version_number: s[:pacticipant_version_number]) : Sequel.&(provider_name: s[:pacticipant_name]) } +
|
26
|
+
selectors.collect{ |s| Sequel.&(provider_name: s[:pacticipant_name], provider_version_number: nil) })
|
27
|
+
)
|
28
|
+
)
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def where_consumer_or_provider_is s
|
33
|
+
where{
|
34
|
+
Sequel.|(
|
35
|
+
s[:pacticipant_version_number] ? Sequel.&(consumer_name: s[:pacticipant_name], consumer_version_number: s[:pacticipant_version_number]) : Sequel.&(consumer_name: s[:pacticipant_name]),
|
36
|
+
s[:pacticipant_version_number] ? Sequel.&(provider_name: s[:pacticipant_name], provider_version_number: s[:pacticipant_version_number]) : Sequel.&(provider_name: s[:pacticipant_name])
|
37
|
+
)
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def order_by_names_ascending_most_recent_first
|
42
|
+
order(
|
43
|
+
Sequel.asc(:consumer_name),
|
44
|
+
Sequel.desc(:consumer_version_order),
|
45
|
+
Sequel.desc(:pact_revision_number),
|
46
|
+
Sequel.asc(:provider_name),
|
47
|
+
Sequel.desc(:provider_version_order),
|
48
|
+
Sequel.desc(:verification_id))
|
49
|
+
end
|
9
50
|
end
|
10
51
|
|
11
52
|
def summary
|
@@ -14,7 +55,6 @@ module PactBroker
|
|
14
55
|
|
15
56
|
# Add logic for ignoring case
|
16
57
|
def <=> other
|
17
|
-
|
18
58
|
comparisons = [
|
19
59
|
compare_name_asc(consumer_name, other.consumer_name),
|
20
60
|
compare_number_desc(consumer_version_order, other.consumer_version_order),
|
data/lib/pact_broker/version.rb
CHANGED
data/script/seed.rb
CHANGED
@@ -53,7 +53,7 @@ TestDataBuilder.new
|
|
53
53
|
.create_label("microservice")
|
54
54
|
.create_provider("Bar")
|
55
55
|
.create_label("microservice")
|
56
|
-
.create_webhook(method: 'GET', url: 'http://localhost:9393
|
56
|
+
.create_webhook(method: 'GET', url: 'http://localhost:9393?url=${pactbroker.pactUrl}', body: '${pactbroker.pactUrl}')
|
57
57
|
.create_consumer_version("1.2.100")
|
58
58
|
.publish_pact
|
59
59
|
.create_verification(provider_version: "1.4.234", success: true, execution_date: DateTime.now - 15)
|
data/script/webhook-server.ru
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
+
require 'rack/utils'
|
2
|
+
|
1
3
|
count = 0
|
2
4
|
run -> (env) {
|
3
5
|
count += 1
|
4
6
|
status = (count % 3 == 0) ? 200 : 500
|
5
|
-
puts
|
7
|
+
puts Rack::Utils.parse_nested_query(env['QUERY_STRING'])
|
8
|
+
puts env['rack.input'].read
|
9
|
+
[status, {}, ["Hello. This might be an error.\n"]]
|
6
10
|
}
|
@@ -7,8 +7,13 @@ describe "Execute a webhook" do
|
|
7
7
|
let(:td) { TestDataBuilder.new }
|
8
8
|
|
9
9
|
before do
|
10
|
-
|
11
|
-
|
10
|
+
ENV['PACT_BROKER_BASE_URL'] = 'http://example.org'
|
11
|
+
td.create_pact_with_hierarchy("Foo", "1", "Bar")
|
12
|
+
.create_webhook(method: 'POST', body: '${pactbroker.pactUrl}')
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
ENV.delete('PACT_BROKER_BASE_URL')
|
12
17
|
end
|
13
18
|
|
14
19
|
let(:path) { "/webhooks/#{td.webhook.uuid}/execute" }
|
@@ -18,7 +23,7 @@ describe "Execute a webhook" do
|
|
18
23
|
|
19
24
|
context "when the execution is successful" do
|
20
25
|
let!(:request) do
|
21
|
-
stub_request(:post, /http/).to_return(:status => 200)
|
26
|
+
stub_request(:post, /http/).with(body: 'http://example.org/pacts/provider/Bar/consumer/Foo/version/1').to_return(:status => 200)
|
22
27
|
end
|
23
28
|
|
24
29
|
it "performs the HTTP request" do
|
@@ -7,6 +7,10 @@ module PactBroker
|
|
7
7
|
module Domain
|
8
8
|
|
9
9
|
describe WebhookRequest do
|
10
|
+
before do
|
11
|
+
allow(PactBroker::Api::PactBrokerUrls).to receive(:pact_url).and_return('http://example.org/pact-url')
|
12
|
+
allow(PactBroker.configuration).to receive(:base_url).and_return('http://example.org')
|
13
|
+
end
|
10
14
|
|
11
15
|
let(:username) { nil }
|
12
16
|
let(:password) { nil }
|
@@ -15,6 +19,7 @@ module PactBroker
|
|
15
19
|
let(:logs) { StringIO.new }
|
16
20
|
let(:execution_logger) { Logger.new(logs) }
|
17
21
|
let(:options) { {failure_log_message: 'oops'}}
|
22
|
+
let(:pact) { instance_double('PactBroker::Domain::Pact') }
|
18
23
|
|
19
24
|
subject do
|
20
25
|
WebhookRequest.new(
|
@@ -26,7 +31,8 @@ module PactBroker
|
|
26
31
|
body: body)
|
27
32
|
end
|
28
33
|
|
29
|
-
let(:logs) { subject.execute(options).logs }
|
34
|
+
let(:logs) { subject.execute(pact, options).logs }
|
35
|
+
|
30
36
|
|
31
37
|
describe "description" do
|
32
38
|
it "returns a brief description of the HTTP request" do
|
@@ -56,15 +62,59 @@ module PactBroker
|
|
56
62
|
to_return(:status => 200, :body => "respbod", :headers => {'Content-Type' => 'text/foo, blah'})
|
57
63
|
end
|
58
64
|
|
65
|
+
describe "when the String body contains a ${pactbroker.pactUrl} parameter" do
|
66
|
+
let!(:http_request) do
|
67
|
+
stub_request(:post, "http://example.org/hook").
|
68
|
+
with(:headers => {'Content-Type'=>'text/plain'}, :body => "<xml><url>http://example.org/pact-url</url></xml>").
|
69
|
+
to_return(:status => 200)
|
70
|
+
end
|
71
|
+
|
72
|
+
let(:body) { "<xml><url>${pactbroker.pactUrl}</url></xml>" }
|
73
|
+
|
74
|
+
it "replaces the token with the live value" do
|
75
|
+
subject.execute(pact, options)
|
76
|
+
expect(http_request).to have_been_made
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "when the JSON body contains a ${pactbroker.pactUrl} parameter" do
|
81
|
+
let!(:http_request) do
|
82
|
+
stub_request(:post, "http://example.org/hook").
|
83
|
+
with(:headers => {'Content-Type'=>'text/plain'}, :body => '{"url":"http://example.org/pact-url"}').
|
84
|
+
to_return(:status => 200)
|
85
|
+
end
|
86
|
+
|
87
|
+
let(:body) { { url: '${pactbroker.pactUrl}' } }
|
88
|
+
|
89
|
+
it "replaces the token with the live value" do
|
90
|
+
subject.execute(pact, options)
|
91
|
+
expect(http_request).to have_been_made
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "when the URL contains a ${pactbroker.pactUrl} parameter" do
|
96
|
+
let!(:http_request) do
|
97
|
+
stub_request(:post, "http://example.org/hook?url=http%3A%2F%2Fexample.org%2Fpact-url").
|
98
|
+
to_return(:status => 200)
|
99
|
+
end
|
100
|
+
|
101
|
+
let(:url) { 'http://example.org/hook?url=${pactbroker.pactUrl}' }
|
102
|
+
|
103
|
+
it "replaces the token with the live value" do
|
104
|
+
subject.execute(pact, options)
|
105
|
+
expect(http_request).to have_been_made
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
59
109
|
it "executes the configured request" do
|
60
|
-
subject.execute(options)
|
110
|
+
subject.execute(pact, options)
|
61
111
|
expect(http_request).to have_been_made
|
62
112
|
end
|
63
113
|
|
64
114
|
it "logs the request" do
|
65
115
|
allow(PactBroker.logger).to receive(:info)
|
66
116
|
expect(PactBroker.logger).to receive(:info).with(/POST.*example.*text.*body/)
|
67
|
-
subject.execute(options)
|
117
|
+
subject.execute(pact, options)
|
68
118
|
end
|
69
119
|
|
70
120
|
it "logs the response" do
|
@@ -72,7 +122,7 @@ module PactBroker
|
|
72
122
|
allow(PactBroker.logger).to receive(:debug)
|
73
123
|
expect(PactBroker.logger).to receive(:info).with(/response.*200/)
|
74
124
|
expect(PactBroker.logger).to receive(:debug).with(/respbod/)
|
75
|
-
subject.execute(options)
|
125
|
+
subject.execute(pact, options)
|
76
126
|
end
|
77
127
|
|
78
128
|
describe "execution logs" do
|
@@ -144,7 +194,7 @@ module PactBroker
|
|
144
194
|
end
|
145
195
|
|
146
196
|
it "uses the credentials" do
|
147
|
-
subject.execute(options)
|
197
|
+
subject.execute(pact, options)
|
148
198
|
expect(http_request_with_basic_auth).to have_been_made
|
149
199
|
end
|
150
200
|
end
|
@@ -160,7 +210,7 @@ module PactBroker
|
|
160
210
|
end
|
161
211
|
|
162
212
|
it "uses SSL" do
|
163
|
-
subject.execute(options)
|
213
|
+
subject.execute(pact, options)
|
164
214
|
expect(https_request).to have_been_made
|
165
215
|
end
|
166
216
|
end
|
@@ -175,7 +225,7 @@ module PactBroker
|
|
175
225
|
end
|
176
226
|
|
177
227
|
it "converts the body to JSON before submitting the request" do
|
178
|
-
subject.execute(options)
|
228
|
+
subject.execute(pact, options)
|
179
229
|
expect(http_request).to have_been_made
|
180
230
|
end
|
181
231
|
end
|
@@ -190,18 +240,18 @@ module PactBroker
|
|
190
240
|
end
|
191
241
|
|
192
242
|
it "executes the request without a body" do
|
193
|
-
subject.execute(options)
|
243
|
+
subject.execute(pact, options)
|
194
244
|
expect(http_request).to have_been_made
|
195
245
|
end
|
196
246
|
end
|
197
247
|
|
198
248
|
context "when the request is successful" do
|
199
249
|
it "returns a WebhookExecutionResult with success=true" do
|
200
|
-
expect(subject.execute(options).success?).to be true
|
250
|
+
expect(subject.execute(pact, options).success?).to be true
|
201
251
|
end
|
202
252
|
|
203
253
|
it "sets the response on the result" do
|
204
|
-
expect(subject.execute(options).response).to be_instance_of(Net::HTTPOK)
|
254
|
+
expect(subject.execute(pact, options).response).to be_instance_of(Net::HTTPOK)
|
205
255
|
end
|
206
256
|
end
|
207
257
|
|
@@ -214,11 +264,11 @@ module PactBroker
|
|
214
264
|
end
|
215
265
|
|
216
266
|
it "returns a WebhookExecutionResult with success=false" do
|
217
|
-
expect(subject.execute(options).success?).to be false
|
267
|
+
expect(subject.execute(pact, options).success?).to be false
|
218
268
|
end
|
219
269
|
|
220
270
|
it "sets the response on the result" do
|
221
|
-
expect(subject.execute(options).response).to be_instance_of(Net::HTTPInternalServerError)
|
271
|
+
expect(subject.execute(pact, options).response).to be_instance_of(Net::HTTPInternalServerError)
|
222
272
|
end
|
223
273
|
end
|
224
274
|
|
@@ -233,15 +283,15 @@ module PactBroker
|
|
233
283
|
it "logs the error" do
|
234
284
|
allow(PactBroker.logger).to receive(:error)
|
235
285
|
expect(PactBroker.logger).to receive(:error).with(/Error.*WebhookTestError.*blah/)
|
236
|
-
subject.execute(options)
|
286
|
+
subject.execute(pact, options)
|
237
287
|
end
|
238
288
|
|
239
289
|
it "returns a WebhookExecutionResult with success=false" do
|
240
|
-
expect(subject.execute(options).success?).to be false
|
290
|
+
expect(subject.execute(pact, options).success?).to be false
|
241
291
|
end
|
242
292
|
|
243
293
|
it "returns a WebhookExecutionResult with an error" do
|
244
|
-
expect(subject.execute(options).error).to be_instance_of WebhookTestError
|
294
|
+
expect(subject.execute(pact, options).error).to be_instance_of WebhookTestError
|
245
295
|
end
|
246
296
|
|
247
297
|
it "logs the failure_log_message" do
|
@@ -11,6 +11,8 @@ module PactBroker
|
|
11
11
|
let(:provider) { Pacticipant.new(name: 'Provider')}
|
12
12
|
let(:request) { instance_double(PactBroker::Domain::WebhookRequest, execute: nil)}
|
13
13
|
let(:options) { double('options') }
|
14
|
+
let(:pact) { double('pact') }
|
15
|
+
|
14
16
|
subject { Webhook.new(request: request, consumer: consumer, provider: provider,) }
|
15
17
|
|
16
18
|
describe "description" do
|
@@ -22,14 +24,14 @@ module PactBroker
|
|
22
24
|
describe "execute" do
|
23
25
|
|
24
26
|
it "executes the request" do
|
25
|
-
expect(request).to receive(:execute).with(options)
|
26
|
-
subject.execute options
|
27
|
+
expect(request).to receive(:execute).with(pact, options)
|
28
|
+
subject.execute pact, options
|
27
29
|
end
|
28
30
|
|
29
31
|
it "logs before and after" do
|
30
32
|
allow(PactBroker.logger).to receive(:info)
|
31
33
|
expect(PactBroker.logger).to receive(:info).with(/Executing/)
|
32
|
-
subject.execute options
|
34
|
+
subject.execute pact, options
|
33
35
|
end
|
34
36
|
end
|
35
37
|
end
|
@@ -555,6 +555,139 @@ module PactBroker
|
|
555
555
|
end
|
556
556
|
end
|
557
557
|
|
558
|
+
describe "find with global latest and tag specified" do
|
559
|
+
subject { shorten_rows(Repository.new.find(selectors, options)) }
|
560
|
+
|
561
|
+
context "with one consumer/version and latest tag specified for all the other pacticipants" do
|
562
|
+
before do
|
563
|
+
td.create_pact_with_hierarchy("A", "1", "B")
|
564
|
+
.create_verification(provider_version: "1")
|
565
|
+
.create_verification(provider_version: "2", number: 2)
|
566
|
+
.use_provider_version("1")
|
567
|
+
.create_provider_version_tag("prod")
|
568
|
+
.create_provider("C")
|
569
|
+
.create_pact
|
570
|
+
.create_verification(provider_version: "3")
|
571
|
+
.use_provider_version("3")
|
572
|
+
.create_provider_version_tag("prod")
|
573
|
+
.create_verification(provider_version: "4", number: 2)
|
574
|
+
end
|
575
|
+
|
576
|
+
let(:selectors) { build_selectors('A'=> '1') }
|
577
|
+
let(:options) { { tag: 'prod', latest: true } }
|
578
|
+
|
579
|
+
it "finds the matrix for the latest tagged versions of each of the other other pacticipants" do
|
580
|
+
expect(subject).to include "A1 B1 n1"
|
581
|
+
expect(subject).to include "A1 C3 n1"
|
582
|
+
expect(subject.size).to eq 2
|
583
|
+
end
|
584
|
+
end
|
585
|
+
|
586
|
+
context "with one consumer/version and latest specified for all the other pacticipants" do
|
587
|
+
before do
|
588
|
+
td.create_pact_with_hierarchy("A", "1", "B")
|
589
|
+
.create_verification(provider_version: "1")
|
590
|
+
.create_verification(provider_version: "2", number: 2)
|
591
|
+
.use_provider_version("1")
|
592
|
+
.create_provider("C")
|
593
|
+
.create_pact
|
594
|
+
.create_verification(provider_version: "3")
|
595
|
+
.create_verification(provider_version: "4", number: 2)
|
596
|
+
end
|
597
|
+
|
598
|
+
let(:selectors) { build_selectors('A'=> '1') }
|
599
|
+
let(:options) { { latest: true } }
|
600
|
+
|
601
|
+
it "finds the matrix for the latest tagged versions of each of the other other pacticipants" do
|
602
|
+
expect(subject).to include "A1 B2 n2"
|
603
|
+
expect(subject).to include "A1 C4 n2"
|
604
|
+
expect(subject.size).to eq 2
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
context "with one pacticipant without a version and latest tag specified for all the other pacticipants" do
|
609
|
+
before do
|
610
|
+
td.create_pact_with_hierarchy("A", "1", "B")
|
611
|
+
.create_verification(provider_version: "1")
|
612
|
+
.create_verification(provider_version: "2", number: 2)
|
613
|
+
.use_provider_version("1")
|
614
|
+
.create_provider_version_tag("prod")
|
615
|
+
.create_provider("C")
|
616
|
+
.create_pact
|
617
|
+
.create_verification(provider_version: "3")
|
618
|
+
.use_provider_version("3")
|
619
|
+
.create_provider_version_tag("prod")
|
620
|
+
.create_verification(provider_version: "4", number: 2)
|
621
|
+
.create_consumer_version("2")
|
622
|
+
.create_pact
|
623
|
+
end
|
624
|
+
|
625
|
+
let(:selectors) { build_selectors('A'=> nil) }
|
626
|
+
let(:options) { { tag: 'prod', latest: true } }
|
627
|
+
|
628
|
+
it "finds the matrix for the latest tagged versions of each of the other other pacticipants" do
|
629
|
+
expect(subject).to include "A1 B1 n1"
|
630
|
+
expect(subject).to include "A1 C3 n1"
|
631
|
+
expect(subject).to include "A2 C? n?"
|
632
|
+
expect(subject.size).to eq 3
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
context "with one pacticipant/version that is both a consumer and provider and latest tag specified for all the other pacticipants" do
|
637
|
+
before do
|
638
|
+
td.create_pact_with_hierarchy("A", "1", "B")
|
639
|
+
.create_consumer_version_tag("prod")
|
640
|
+
.create_verification(provider_version: "1")
|
641
|
+
.use_provider_version("1")
|
642
|
+
.use_consumer("B")
|
643
|
+
.use_consumer_version("1")
|
644
|
+
.create_provider("C")
|
645
|
+
.create_pact
|
646
|
+
.create_verification(provider_version: "3")
|
647
|
+
.use_provider_version("3")
|
648
|
+
.create_provider_version_tag("prod")
|
649
|
+
.create_verification(provider_version: "4", number: 2)
|
650
|
+
end
|
651
|
+
|
652
|
+
let(:selectors) { build_selectors('B'=> '1') }
|
653
|
+
let(:options) { { tag: 'prod', latest: true } }
|
654
|
+
|
655
|
+
it "finds the matrix for the latest tagged versions of each of the other other pacticipants" do
|
656
|
+
expect(subject).to include "A1 B1 n1"
|
657
|
+
expect(subject).to include "B1 C3 n1"
|
658
|
+
expect(subject.size).to eq 2
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
662
|
+
context "with one pacticipant/latest tag and latest tag specified for all the other pacticipants" do
|
663
|
+
before do
|
664
|
+
td.create_pact_with_hierarchy("A", "1", "B")
|
665
|
+
.create_consumer_version_tag("dev")
|
666
|
+
.create_verification(provider_version: "1")
|
667
|
+
.use_provider_version("1")
|
668
|
+
.create_provider_version_tag("prod")
|
669
|
+
.create_provider("C")
|
670
|
+
.create_pact
|
671
|
+
.create_verification(provider_version: "3")
|
672
|
+
.use_provider_version("3")
|
673
|
+
.create_provider_version_tag("prod")
|
674
|
+
.create_verification(provider_version: "4", number: 2)
|
675
|
+
end
|
676
|
+
|
677
|
+
let(:selectors) { [{ pacticipant_name: 'A', latest: true, tag: 'dev' } ] }
|
678
|
+
let(:options) { { tag: 'prod', latest: true } }
|
679
|
+
|
680
|
+
it "finds the matrix for the latest tagged versions of each of the other other pacticipants" do
|
681
|
+
expect(subject).to include "A1 B1 n1"
|
682
|
+
expect(subject).to include "A1 C3 n1"
|
683
|
+
expect(subject).to_not include "A1 C4 n2"
|
684
|
+
expect(subject.size).to eq 2
|
685
|
+
end
|
686
|
+
end
|
687
|
+
|
688
|
+
|
689
|
+
end
|
690
|
+
|
558
691
|
describe "#find_for_consumer_and_provider" do
|
559
692
|
before do
|
560
693
|
TestDataBuilder.new
|
@@ -82,6 +82,17 @@ Pact.provider_states_for "Pact Broker Client" do
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
+
provider_state "the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6 (tagged prod) and version 5.6.7" do
|
86
|
+
set_up do
|
87
|
+
TestDataBuilder.new
|
88
|
+
.create_pact_with_hierarchy("Foo", "1.2.3", "Bar")
|
89
|
+
.create_verification(provider_version: "4.5.6")
|
90
|
+
.use_provider_version("4.5.6")
|
91
|
+
.create_provider_version_tag("prod")
|
92
|
+
.create_verification(provider_version: "5.6.7", number: 2)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
85
96
|
provider_state "the 'Pricing Service' does not exist in the pact-broker" do
|
86
97
|
no_op
|
87
98
|
end
|
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.9.0.beta.5
|
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: 2017-11-
|
13
|
+
date: 2017-11-09 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: httparty
|
@@ -774,6 +774,7 @@ files:
|
|
774
774
|
- lib/rack/pact_broker/database_transaction.rb
|
775
775
|
- lib/rack/pact_broker/invalid_uri_protection.rb
|
776
776
|
- lib/rack/pact_broker/no_auth.rb
|
777
|
+
- lib/rack/pact_broker/store_base_url.rb
|
777
778
|
- lib/rack/pact_broker/ui_authentication.rb
|
778
779
|
- pact_broker.gemspec
|
779
780
|
- pact_broker_client-pact_broker.json
|