pact_broker-client 1.30.0 → 1.35.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +23 -0
- data/CHANGELOG.md +46 -0
- data/README.md +15 -3
- data/doc/pacts/markdown/Pact Broker Client - Pact Broker.md +48 -8
- data/lib/pact_broker/client/base_client.rb +11 -9
- data/lib/pact_broker/client/cli/broker.rb +3 -1
- data/lib/pact_broker/client/matrix.rb +3 -1
- data/lib/pact_broker/client/matrix/text_formatter.rb +44 -11
- data/lib/pact_broker/client/pacts/list_latest_versions.rb +1 -1
- data/lib/pact_broker/client/publish_pacts.rb +13 -5
- data/lib/pact_broker/client/version.rb +1 -1
- data/pact-broker-client.gemspec +3 -1
- data/spec/lib/pact_broker/client/base_client_spec.rb +62 -4
- data/spec/lib/pact_broker/client/matrix/text_formatter_spec.rb +29 -4
- data/spec/lib/pact_broker/client/publish_pacts_spec.rb +20 -1
- data/spec/pacts/pact_broker_client-pact_broker.json +48 -8
- data/spec/support/matrix.json +6 -1
- data/spec/support/matrix.txt +3 -3
- data/spec/support/matrix_error.txt +3 -3
- data/spec/support/matrix_with_results.txt +10 -0
- metadata +42 -6
- data/.travis.yml +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1bf1176c39519652e60c6aab383a941a2dd5a1c8e968b746741a290e68c736e9
|
4
|
+
data.tar.gz: 04b1f3aa9f25b353e61eb558d393d108750cd97b4645fe81313b1d04dca33ba5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cbb4fe27ce2979d3daea2c597ca7509b6d4136ac53d139a738fd672f30d114fcce23ce4f3ba3c108aef13ec88b9793715bf57ec05a2fda6255dfcd7ed9c99875
|
7
|
+
data.tar.gz: 443c3e2e5fb75bcbfa3850ce1498f859c45872145f813c50b260a9a7d28a32f5aa7618c1f55b0c798b34975ec7b35d7e44b0937c6bd2575dea1b86356eb8ca5b
|
@@ -0,0 +1,23 @@
|
|
1
|
+
name: Test
|
2
|
+
|
3
|
+
on: push
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
runs-on: "ubuntu-latest"
|
8
|
+
continue-on-error: ${{ matrix.experimental }}
|
9
|
+
strategy:
|
10
|
+
fail-fast: false
|
11
|
+
matrix:
|
12
|
+
ruby_version: ["2.2", "2.7"]
|
13
|
+
experimental: [false]
|
14
|
+
include:
|
15
|
+
- ruby_version: "3.0"
|
16
|
+
experimental: true
|
17
|
+
steps:
|
18
|
+
- uses: actions/checkout@v2
|
19
|
+
- uses: ruby/setup-ruby@v1
|
20
|
+
with:
|
21
|
+
ruby-version: ${{ matrix.ruby_version }}
|
22
|
+
- run: "bundle install"
|
23
|
+
- run: "bundle exec rake"
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,49 @@
|
|
1
|
+
<a name="v1.35.0"></a>
|
2
|
+
### v1.35.0 (2021-01-21)
|
3
|
+
|
4
|
+
#### Features
|
5
|
+
|
6
|
+
* **can-i-deploy**
|
7
|
+
* display links to verification results in the output of can-i-deploy when using text format ([976950d](/../../commit/976950d))
|
8
|
+
|
9
|
+
<a name="v1.34.0"></a>
|
10
|
+
### v1.34.0 (2020-11-20)
|
11
|
+
|
12
|
+
#### Features
|
13
|
+
|
14
|
+
* **pact publish**
|
15
|
+
* strip new lines from version numbers and tags ([5842d24](/../../commit/5842d24))
|
16
|
+
|
17
|
+
* **publish**
|
18
|
+
* update output text when pact already exists and merging ([9b849d3](/../../commit/9b849d3))
|
19
|
+
|
20
|
+
<a name="v1.33.0"></a>
|
21
|
+
### v1.33.0 (2020-11-10)
|
22
|
+
|
23
|
+
#### Features
|
24
|
+
|
25
|
+
* **publish**
|
26
|
+
* allow pacts to be merged on the server side ([bd80f10](/../../commit/bd80f10))
|
27
|
+
|
28
|
+
<a name="v1.32.0"></a>
|
29
|
+
### v1.32.0 (2020-10-26)
|
30
|
+
|
31
|
+
#### Features
|
32
|
+
|
33
|
+
* Improve HTTP errors handling (#76) ([d8eaf16](/../../commit/d8eaf16))
|
34
|
+
|
35
|
+
#### Bug Fixes
|
36
|
+
|
37
|
+
* **list-latest-pact-versions**
|
38
|
+
* correct json output ([cf77666](/../../commit/cf77666))
|
39
|
+
|
40
|
+
<a name="v1.31.0"></a>
|
41
|
+
### v1.31.0 (2020-10-22)
|
42
|
+
|
43
|
+
#### Features
|
44
|
+
|
45
|
+
* update thor dependancy (#75) ([2078f31](/../../commit/2078f31))
|
46
|
+
|
1
47
|
<a name="v1.30.0"></a>
|
2
48
|
### v1.30.0 (2020-10-09)
|
3
49
|
|
data/README.md
CHANGED
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
A client for the Pact Broker. Publishes and retrieves pacts, verification results, pacticipants, pacticipant versions and tags. The functionality is available via a CLI, or via Ruby Rake tasks. You can also use the [Pact CLI Docker image](https://hub.docker.com/r/pactfoundation/pact-cli).
|
4
4
|
|
5
|
-
|
5
|
+
![Build status](https://github.com/pact-foundation/pact_broker-client/workflows/Test/badge.svg)
|
6
|
+
|
7
|
+
[![Gem Version](https://badge.fury.io/rb/pact_broker-client.svg)](http://badge.fury.io/rb/pact_broker-client)
|
6
8
|
|
7
9
|
![Trigger update to docs.pact.io](https://github.com/pact-foundation/pact_broker-client/workflows/Trigger%20update%20to%20docs.pact.io/badge.svg)
|
8
10
|
|
@@ -16,9 +18,19 @@ Download the latest [pact-ruby-standalone][pact-ruby-standalone] package. You do
|
|
16
18
|
|
17
19
|
Add `gem 'pact_broker-client'` to your Gemfile and run `bundle install`, or install the gem directly by running `gem install pact_broker-client`.
|
18
20
|
|
21
|
+
## Connecting to a Pact Broker with a self signed certificate
|
22
|
+
|
23
|
+
To connect to a Pact Broker that uses custom SSL cerificates, set the environment variable `$SSL_CERT_FILE` or `$SSL_CERT_DIR` to a path that contains the appropriate certificate. Read more at https://docs.pact.io/pact_broker/advanced_topics/using-tls#for-non-jvm
|
24
|
+
|
19
25
|
## Usage - CLI
|
20
26
|
|
21
|
-
|
27
|
+
The Pact Broker base URL can be specified either using the environment variable `$PACT_BROKER_BASE_URL` or the `-b` or `--broker-base-url` parameters.
|
28
|
+
|
29
|
+
Pact Broker authentication can be performed either using basic auth or a bearer token.
|
30
|
+
|
31
|
+
Basic auth parameters can be specified using the `$PACT_BROKER_USERNAME` and `$PACT_BROKER_PASSWORD` environment variables, or the `-u` or `--broker-username` and `-p` or `--broker-password` parameters.
|
32
|
+
|
33
|
+
Authentication using a bearer token can be specified using the environment variable `$PACT_BROKER_TOKEN` or the `-k` or `--broker-token` parameters. This authentication system is used by [Pactflow](pactflow.io).
|
22
34
|
|
23
35
|
### publish
|
24
36
|
|
@@ -188,7 +200,7 @@ Can I deploy all the applications in my monorepo to prod?
|
|
188
200
|
--pacticipant B --version a7e28207 \
|
189
201
|
--pacticipant C --version a7e28207 \
|
190
202
|
--to prod \
|
191
|
-
--broker-base-url BROKER_BASE_URL
|
203
|
+
--broker-base-url BROKER_BASE_URL
|
192
204
|
|
193
205
|
Mobile provider use case - can I deploy version b80e7b1b of Bar, all versions of Foo with tag "prod", and the latest version tagged "prod" of any other automatically calculated dependencies together? (Eg. where Bar is a provider and Foo is a mobile consumer with multiple versions in production, and Bar also has its own providers it needs to be compatible with.)
|
194
206
|
|
@@ -164,7 +164,12 @@ Pact Broker will respond with:
|
|
164
164
|
},
|
165
165
|
"verificationResult": {
|
166
166
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
167
|
-
"success": true
|
167
|
+
"success": true,
|
168
|
+
"_links": {
|
169
|
+
"self": {
|
170
|
+
"href": "http://result"
|
171
|
+
}
|
172
|
+
}
|
168
173
|
},
|
169
174
|
"pact": {
|
170
175
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
@@ -185,7 +190,12 @@ Pact Broker will respond with:
|
|
185
190
|
},
|
186
191
|
"verificationResult": {
|
187
192
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
188
|
-
"success": true
|
193
|
+
"success": true,
|
194
|
+
"_links": {
|
195
|
+
"self": {
|
196
|
+
"href": "http://result"
|
197
|
+
}
|
198
|
+
}
|
189
199
|
},
|
190
200
|
"pact": {
|
191
201
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
@@ -233,7 +243,12 @@ Pact Broker will respond with:
|
|
233
243
|
},
|
234
244
|
"verificationResult": {
|
235
245
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
236
|
-
"success": true
|
246
|
+
"success": true,
|
247
|
+
"_links": {
|
248
|
+
"self": {
|
249
|
+
"href": "http://result"
|
250
|
+
}
|
251
|
+
}
|
237
252
|
},
|
238
253
|
"pact": {
|
239
254
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
@@ -281,7 +296,12 @@ Pact Broker will respond with:
|
|
281
296
|
},
|
282
297
|
"verificationResult": {
|
283
298
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
284
|
-
"success": true
|
299
|
+
"success": true,
|
300
|
+
"_links": {
|
301
|
+
"self": {
|
302
|
+
"href": "http://result"
|
303
|
+
}
|
304
|
+
}
|
285
305
|
},
|
286
306
|
"pact": {
|
287
307
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
@@ -329,7 +349,12 @@ Pact Broker will respond with:
|
|
329
349
|
},
|
330
350
|
"verificationResult": {
|
331
351
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
332
|
-
"success": true
|
352
|
+
"success": true,
|
353
|
+
"_links": {
|
354
|
+
"self": {
|
355
|
+
"href": "http://result"
|
356
|
+
}
|
357
|
+
}
|
333
358
|
},
|
334
359
|
"pact": {
|
335
360
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
@@ -413,7 +438,12 @@ Pact Broker will respond with:
|
|
413
438
|
},
|
414
439
|
"verificationResult": {
|
415
440
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
416
|
-
"success": true
|
441
|
+
"success": true,
|
442
|
+
"_links": {
|
443
|
+
"self": {
|
444
|
+
"href": "http://result"
|
445
|
+
}
|
446
|
+
}
|
417
447
|
},
|
418
448
|
"pact": {
|
419
449
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
@@ -484,7 +514,12 @@ Pact Broker will respond with:
|
|
484
514
|
},
|
485
515
|
"verificationResult": {
|
486
516
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
487
|
-
"success": true
|
517
|
+
"success": true,
|
518
|
+
"_links": {
|
519
|
+
"self": {
|
520
|
+
"href": "http://result"
|
521
|
+
}
|
522
|
+
}
|
488
523
|
},
|
489
524
|
"pact": {
|
490
525
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
@@ -735,7 +770,12 @@ Pact Broker will respond with:
|
|
735
770
|
},
|
736
771
|
"verificationResult": {
|
737
772
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
738
|
-
"success": true
|
773
|
+
"success": true,
|
774
|
+
"_links": {
|
775
|
+
"self": {
|
776
|
+
"href": "http://result"
|
777
|
+
}
|
778
|
+
}
|
739
779
|
},
|
740
780
|
"pact": {
|
741
781
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'erb'
|
2
4
|
require 'httparty'
|
3
5
|
require 'pact_broker/client/error'
|
@@ -30,6 +32,12 @@ module PactBroker
|
|
30
32
|
end
|
31
33
|
|
32
34
|
class BaseClient
|
35
|
+
ERROR_CODE_MAPPING = {
|
36
|
+
401 => "Authentication failed",
|
37
|
+
403 => "Authorization failed (insufficient permissions)",
|
38
|
+
409 => "Potential duplicate pacticipants"
|
39
|
+
}.freeze
|
40
|
+
|
33
41
|
include UrlHelpers
|
34
42
|
include HTTParty
|
35
43
|
include StringToSymbol
|
@@ -69,14 +77,8 @@ module PactBroker
|
|
69
77
|
yield response
|
70
78
|
elsif response.code == 404
|
71
79
|
nil
|
72
|
-
elsif response.code
|
73
|
-
message =
|
74
|
-
if response.body && response.body.size > 0
|
75
|
-
message = message + ": #{response.body}"
|
76
|
-
end
|
77
|
-
raise Error.new(message)
|
78
|
-
elsif response.code == 401
|
79
|
-
message = "Authentication failed"
|
80
|
+
elsif ERROR_CODE_MAPPING.key?(response.code)
|
81
|
+
message = ERROR_CODE_MAPPING.fetch(response.code)
|
80
82
|
if response.body && response.body.size > 0
|
81
83
|
message = message + ": #{response.body}"
|
82
84
|
end
|
@@ -93,7 +95,7 @@ module PactBroker
|
|
93
95
|
response.body
|
94
96
|
end
|
95
97
|
rescue
|
96
|
-
raise Error.new(response.body)
|
98
|
+
raise Error.new("status=#{response.code} #{response.body}")
|
97
99
|
end
|
98
100
|
raise Error.new(error_message)
|
99
101
|
end
|
@@ -50,6 +50,7 @@ module PactBroker
|
|
50
50
|
method_option :broker_token, aliases: "-k", desc: "Pact Broker bearer token"
|
51
51
|
method_option :tag, aliases: "-t", type: :array, banner: "TAG", desc: "Tag name for consumer version. Can be specified multiple times."
|
52
52
|
method_option :tag_with_git_branch, aliases: "-g", type: :boolean, default: false, required: false, desc: "Tag consumer version with the name of the current git branch. Default: false"
|
53
|
+
method_option :merge, type: :boolean, default: false, require: false, desc: "If a pact already exists for this consumer version and provider, merge the contents. Useful when running Pact tests concurrently on different build nodes."
|
53
54
|
method_option :verbose, aliases: "-v", type: :boolean, default: false, required: false, desc: "Verbose output. Default: false"
|
54
55
|
|
55
56
|
def publish(*pact_files)
|
@@ -209,13 +210,14 @@ module PactBroker
|
|
209
210
|
|
210
211
|
def publish_pacts pact_files
|
211
212
|
require 'pact_broker/client/publish_pacts'
|
213
|
+
write_options = options[:merge] ? { write: :merge } : {}
|
212
214
|
|
213
215
|
PactBroker::Client::PublishPacts.call(
|
214
216
|
options.broker_base_url,
|
215
217
|
file_list(pact_files),
|
216
218
|
options.consumer_app_version,
|
217
219
|
tags,
|
218
|
-
pact_broker_client_options
|
220
|
+
pact_broker_client_options.merge(write_options)
|
219
221
|
)
|
220
222
|
end
|
221
223
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'base_client'
|
2
4
|
require 'pact_broker/client/matrix/resource'
|
3
5
|
|
@@ -39,7 +41,7 @@ module PactBroker
|
|
39
41
|
response.body
|
40
42
|
end
|
41
43
|
rescue
|
42
|
-
raise Error.new(response.body)
|
44
|
+
raise Error.new("status=#{response.code} #{response.body}")
|
43
45
|
end
|
44
46
|
raise Error.new(error_message)
|
45
47
|
end
|
@@ -1,41 +1,74 @@
|
|
1
1
|
require 'table_print'
|
2
|
+
require 'dig_rb'
|
2
3
|
|
3
4
|
module PactBroker
|
4
5
|
module Client
|
5
6
|
class Matrix
|
6
7
|
class TextFormatter
|
7
8
|
|
8
|
-
Line = Struct.new(:consumer, :consumer_version, :provider, :provider_version, :success)
|
9
|
+
Line = Struct.new(:consumer, :consumer_version, :provider, :provider_version, :success, :ref)
|
9
10
|
|
10
11
|
OPTIONS = [
|
11
12
|
{ consumer: {} },
|
12
13
|
{ consumer_version: {display_name: 'C.VERSION'} },
|
13
14
|
{ provider: {} },
|
14
15
|
{ provider_version: {display_name: 'P.VERSION'} },
|
15
|
-
{ success: {display_name: 'SUCCESS?'} }
|
16
|
+
{ success: {display_name: 'SUCCESS?'} },
|
17
|
+
{ ref: { display_name: 'RESULT#' }}
|
16
18
|
]
|
17
19
|
|
18
20
|
def self.call(matrix)
|
19
21
|
matrix_rows = matrix[:matrix]
|
20
22
|
return "" if matrix_rows.size == 0
|
21
|
-
|
23
|
+
verification_result_number = 0
|
24
|
+
data = matrix_rows.each_with_index.collect do | line |
|
25
|
+
has_verification_result_url = lookup(line, nil, :verificationResult, :_links, :self, :href)
|
26
|
+
if has_verification_result_url
|
27
|
+
verification_result_number += 1
|
28
|
+
end
|
22
29
|
Line.new(
|
23
|
-
lookup(line, :consumer, :name),
|
24
|
-
lookup(line, :consumer, :version, :number),
|
25
|
-
lookup(line, :provider, :name),
|
26
|
-
lookup(line, :provider, :version, :number),
|
27
|
-
lookup(line, :verificationResult, :success).to_s
|
30
|
+
lookup(line, "???", :consumer, :name),
|
31
|
+
lookup(line, "???", :consumer, :version, :number),
|
32
|
+
lookup(line, "???", :provider, :name) ,
|
33
|
+
lookup(line, "???", :provider, :version, :number),
|
34
|
+
(lookup(line, "???", :verificationResult, :success)).to_s,
|
35
|
+
has_verification_result_url ? verification_result_number : ""
|
28
36
|
)
|
29
37
|
end
|
30
38
|
|
31
39
|
printer = TablePrint::Printer.new(data, OPTIONS)
|
32
|
-
printer.table_print
|
40
|
+
printer.table_print + verification_result_urls_text(matrix)
|
33
41
|
end
|
34
42
|
|
35
|
-
def self.lookup line, *keys
|
43
|
+
def self.lookup line, default, *keys
|
36
44
|
keys.reduce(line) { | line, key | line[key] }
|
37
45
|
rescue NoMethodError
|
38
|
-
|
46
|
+
default
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.verification_results_urls_and_successes(matrix)
|
50
|
+
(matrix[:matrix] || []).collect do | row |
|
51
|
+
url = row.dig(:verificationResult, :_links, :self, :href)
|
52
|
+
if url
|
53
|
+
success = row.dig(:verificationResult, :success)
|
54
|
+
[url, success]
|
55
|
+
else
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
end.compact
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.verification_result_urls_text(matrix)
|
62
|
+
text = self.verification_results_urls_and_successes(matrix).each_with_index.collect do |(url, success), i|
|
63
|
+
status = success ? 'success' : 'failure'
|
64
|
+
"#{i+1}. #{url} (#{status})"
|
65
|
+
end.join("\n")
|
66
|
+
|
67
|
+
if text.size > 0
|
68
|
+
"\n\nVERIFICATION RESULTS\n--------------------\n#{text}"
|
69
|
+
else
|
70
|
+
text
|
71
|
+
end
|
39
72
|
end
|
40
73
|
end
|
41
74
|
end
|
@@ -16,8 +16,8 @@ module PactBroker
|
|
16
16
|
def initialize pact_broker_base_url, pact_file_paths, consumer_version, tags, pact_broker_client_options={}
|
17
17
|
@pact_broker_base_url = pact_broker_base_url
|
18
18
|
@pact_file_paths = pact_file_paths
|
19
|
-
@consumer_version = consumer_version
|
20
|
-
@tags = tags
|
19
|
+
@consumer_version = consumer_version.respond_to?(:strip) ? consumer_version.strip : consumer_version
|
20
|
+
@tags = tags ? tags.collect{ |tag| tag.respond_to?(:strip) ? tag.strip : tag } : tags
|
21
21
|
@pact_broker_client_options = pact_broker_client_options
|
22
22
|
end
|
23
23
|
|
@@ -37,6 +37,10 @@ module PactBroker
|
|
37
37
|
@pact_broker_client ||= PactBroker::Client::PactBrokerClient.new(base_url: pact_broker_base_url, client_options: pact_broker_client_options)
|
38
38
|
end
|
39
39
|
|
40
|
+
def merge_on_server?
|
41
|
+
pact_broker_client_options[:write] == :merge
|
42
|
+
end
|
43
|
+
|
40
44
|
def publish_pacts
|
41
45
|
pact_files.group_by(&:pact_name).collect do | pact_name, pact_files |
|
42
46
|
$stdout.puts "Merging #{pact_files.collect(&:path).join(", ")}" if pact_files.size > 1
|
@@ -77,13 +81,13 @@ module PactBroker
|
|
77
81
|
versions = pact_broker_client.pacticipants.versions
|
78
82
|
Retry.while_error do
|
79
83
|
consumer_names.collect do | consumer_name |
|
80
|
-
$stdout.puts "Tagging version #{consumer_version} of #{consumer_name} as #{tag.inspect}"
|
81
84
|
versions.tag(pacticipant: consumer_name, version: consumer_version, tag: tag)
|
85
|
+
$stdout.puts "Tagged version #{consumer_version} of #{consumer_name} as #{tag.inspect}"
|
82
86
|
true
|
83
87
|
end
|
84
88
|
end
|
85
89
|
rescue => e
|
86
|
-
$stderr.puts "Failed to tag
|
90
|
+
$stderr.puts "Failed to tag version due to error: #{e.class} - #{e}"
|
87
91
|
false
|
88
92
|
end
|
89
93
|
|
@@ -91,7 +95,11 @@ module PactBroker
|
|
91
95
|
Retry.while_error do
|
92
96
|
pacts = pact_broker_client.pacticipants.versions.pacts
|
93
97
|
if pacts.version_published?(consumer: pact.consumer_name, provider: pact.provider_name, consumer_version: consumer_version)
|
94
|
-
|
98
|
+
if merge_on_server?
|
99
|
+
$stdout.puts "A pact for this consumer version is already published. Merging contents."
|
100
|
+
else
|
101
|
+
$stdout.puts ::Term::ANSIColor.yellow("A pact for this consumer version is already published. Overwriting. (Note: Overwriting pacts is not recommended as it can lead to race conditions. Best practice is to provide a unique consumer version number for each publication.)")
|
102
|
+
end
|
95
103
|
end
|
96
104
|
|
97
105
|
latest_pact_url = pacts.publish(pact_hash: pact, consumer_version: consumer_version)
|
data/pact-broker-client.gemspec
CHANGED
@@ -24,11 +24,13 @@ Gem::Specification.new do |gem|
|
|
24
24
|
gem.add_runtime_dependency 'httparty', '~>0.18'
|
25
25
|
gem.add_runtime_dependency 'term-ansicolor', '~> 1.7'
|
26
26
|
gem.add_runtime_dependency 'table_print', '~> 1.5'
|
27
|
-
gem.add_runtime_dependency 'thor', '
|
27
|
+
gem.add_runtime_dependency 'thor', '>= 0.20', '< 2.0'
|
28
28
|
gem.add_runtime_dependency 'rake', '~> 13.0' #For FileList
|
29
|
+
gem.add_runtime_dependency 'dig_rb', '~> 1.0'
|
29
30
|
|
30
31
|
gem.add_development_dependency 'fakefs', '~> 0.4'
|
31
32
|
gem.add_development_dependency 'webmock', '~> 3.0'
|
32
33
|
gem.add_development_dependency 'conventional-changelog', '~>1.3'
|
33
34
|
gem.add_development_dependency 'pact', '~> 1.16'
|
35
|
+
gem.add_development_dependency 'pact-support', '1.15.0'
|
34
36
|
end
|
@@ -2,10 +2,11 @@ require 'pact_broker/client/base_client'
|
|
2
2
|
module PactBroker
|
3
3
|
module Client
|
4
4
|
describe BaseClient do
|
5
|
-
|
6
|
-
|
5
|
+
subject { BaseClient.new(base_url: base_url) }
|
6
|
+
|
7
|
+
let(:base_url) { 'http://pact_broker_base_url'}
|
7
8
|
|
8
|
-
|
9
|
+
describe '#initialize' do
|
9
10
|
let(:username) { 'pact_repo_username'}
|
10
11
|
let(:password) { 'pact_repo_password'}
|
11
12
|
let(:token) { '123456789' }
|
@@ -119,6 +120,63 @@ module PactBroker
|
|
119
120
|
end
|
120
121
|
end
|
121
122
|
end
|
123
|
+
|
124
|
+
describe '#handle_response' do
|
125
|
+
let(:response) { double('Response', success?: true) }
|
126
|
+
|
127
|
+
it 'yields response object' do
|
128
|
+
expect { |block| subject.handle_response(response, &block) }.to yield_with_args(response)
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'with 404 response' do
|
132
|
+
let(:response) { double('Response', success?: false, code: 404) }
|
133
|
+
it 'returns nil' do
|
134
|
+
expect(subject.handle_response(response)).to be_nil
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'with 401 response' do
|
139
|
+
let(:response) { double('Response', success?: false, code: 401, body: 'body') }
|
140
|
+
it 'raise an exception with meaningful message' do
|
141
|
+
expect { subject.handle_response(response) }
|
142
|
+
.to raise_error(PactBroker::Client::Error, "Authentication failed: body")
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'with 403 response' do
|
147
|
+
let(:response) { double('Response', success?: false, code: 403, body: 'body') }
|
148
|
+
it 'raise an exception with meaningful message' do
|
149
|
+
expect { subject.handle_response(response) }
|
150
|
+
.to raise_error(PactBroker::Client::Error, "Authorization failed (insufficient permissions): body")
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'with 409 response' do
|
155
|
+
let(:response) { double('Response', success?: false, code: 409, body: 'body') }
|
156
|
+
it 'raise an exception with meaningful message' do
|
157
|
+
expect { subject.handle_response(response) }
|
158
|
+
.to raise_error(PactBroker::Client::Error, "Potential duplicate pacticipants: body")
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context 'with unsuccessful JSON response' do
|
163
|
+
let(:response) do
|
164
|
+
double('Response', success?: false, code: 500, body: '{"errors": ["Internal server error"]}')
|
165
|
+
end
|
166
|
+
it 'raise an exception with meaningful message' do
|
167
|
+
expect { subject.handle_response(response) }
|
168
|
+
.to raise_error(PactBroker::Client::Error, "Internal server error")
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context 'with unsucessful nono-JSON response ' do
|
173
|
+
let(:response) { double('Response', success?: false, code: 500, body: 'Internal server error') }
|
174
|
+
it 'raise an exception with meaningful message' do
|
175
|
+
expect { subject.handle_response(response) }
|
176
|
+
.to raise_error(PactBroker::Client::Error, "status=500 Internal server error")
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
122
180
|
end
|
123
181
|
end
|
124
|
-
end
|
182
|
+
end
|
@@ -1,29 +1,54 @@
|
|
1
|
+
require 'pact_broker/client/matrix/resource'
|
1
2
|
require 'pact_broker/client/matrix/text_formatter'
|
2
3
|
|
3
4
|
module PactBroker
|
4
5
|
module Client
|
5
6
|
describe Matrix::TextFormatter do
|
6
|
-
let(:
|
7
|
+
let(:matrix) { PactBroker::Client::Matrix::Resource.new(JSON.parse(File.read('spec/support/matrix.json'), symbolize_names: true)) }
|
7
8
|
let(:expected_matrix_lines) { File.read('spec/support/matrix.txt') }
|
8
9
|
|
9
10
|
# SublimeText removes whitespace from the end of files when you save them,
|
10
11
|
# so removing trailing whitespace before comparing
|
11
|
-
|
12
|
+
def strip_trailing_whitespace(text)
|
13
|
+
text.split("\n").collect(&:strip).join("\n")
|
14
|
+
end
|
15
|
+
|
16
|
+
subject { strip_trailing_whitespace(Matrix::TextFormatter.call(matrix)) }
|
12
17
|
|
13
18
|
context "with valid data" do
|
14
19
|
it "it has the right text" do
|
15
|
-
expect(subject).to
|
20
|
+
expect(subject).to start_with expected_matrix_lines
|
16
21
|
end
|
17
22
|
end
|
18
23
|
|
19
24
|
context "with invalid data" do
|
20
25
|
let(:expected_matrix_lines) { File.read('spec/support/matrix_error.txt') }
|
21
|
-
let(:
|
26
|
+
let(:matrix) { PactBroker::Client::Matrix::Resource.new(matrix: [{}]) }
|
22
27
|
|
23
28
|
it "doesn't blow up" do
|
24
29
|
expect(subject).to eq expected_matrix_lines
|
25
30
|
end
|
26
31
|
end
|
32
|
+
|
33
|
+
context "when some rows have a verification result URL and some don't" do
|
34
|
+
let(:matrix_lines) do
|
35
|
+
line_creator = -> { JSON.parse(File.read('spec/support/matrix.json'), symbolize_names: true)[:matrix].first }
|
36
|
+
line_1 = line_creator.call
|
37
|
+
line_2 = line_creator.call
|
38
|
+
line_3 = line_creator.call
|
39
|
+
line_2[:verificationResult] = nil
|
40
|
+
line_3[:verificationResult][:success] = false
|
41
|
+
[line_1, line_2, line_3]
|
42
|
+
end
|
43
|
+
|
44
|
+
let(:matrix) { PactBroker::Client::Matrix::Resource.new(matrix: matrix_lines) }
|
45
|
+
|
46
|
+
let(:expected_matrix_lines) { File.read('spec/support/matrix_with_results.txt') }
|
47
|
+
|
48
|
+
it "only provides a result number for the lines that have a result URL" do
|
49
|
+
expect(subject).to eq expected_matrix_lines
|
50
|
+
end
|
51
|
+
end
|
27
52
|
end
|
28
53
|
end
|
29
54
|
end
|
@@ -62,12 +62,12 @@ module PactBroker
|
|
62
62
|
end
|
63
63
|
|
64
64
|
context "when publishing is successful" do
|
65
|
-
|
66
65
|
it "puts the location of the latest pact" do
|
67
66
|
allow($stdout).to receive(:puts)
|
68
67
|
expect($stdout).to receive(:puts).with(/#{latest_pact_url}/)
|
69
68
|
subject.call
|
70
69
|
end
|
70
|
+
|
71
71
|
it "returns true" do
|
72
72
|
expect(subject.call).to be true
|
73
73
|
end
|
@@ -142,6 +142,15 @@ module PactBroker
|
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
145
|
+
context "when consumer_version has a new line" do
|
146
|
+
let(:consumer_version) { "1\n" }
|
147
|
+
|
148
|
+
it "strips the new line" do
|
149
|
+
expect(pacts_client).to receive(:publish).with(pact_hash: pact_hash, consumer_version: "1")
|
150
|
+
subject.call
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
145
154
|
context "when pact_broker_base_url is blank" do
|
146
155
|
let(:pact_broker_base_url) { " " }
|
147
156
|
it "raises a validation errror" do
|
@@ -164,6 +173,16 @@ module PactBroker
|
|
164
173
|
subject.call
|
165
174
|
end
|
166
175
|
|
176
|
+
context "when the tag has a new line on the end of it" do
|
177
|
+
let(:tags) { ["foo\n"] }
|
178
|
+
|
179
|
+
it "strips the newline" do
|
180
|
+
expect(pact_versions_client).to receive(:tag).with({pacticipant: "Consumer",
|
181
|
+
version: consumer_version, tag: "foo"})
|
182
|
+
subject.call
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
167
186
|
context "when an error occurs tagging the pact" do
|
168
187
|
|
169
188
|
before do
|
@@ -221,7 +221,12 @@
|
|
221
221
|
},
|
222
222
|
"verificationResult": {
|
223
223
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
224
|
-
"success": true
|
224
|
+
"success": true,
|
225
|
+
"_links": {
|
226
|
+
"self": {
|
227
|
+
"href": "http://result"
|
228
|
+
}
|
229
|
+
}
|
225
230
|
},
|
226
231
|
"pact": {
|
227
232
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
@@ -271,7 +276,12 @@
|
|
271
276
|
},
|
272
277
|
"verificationResult": {
|
273
278
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
274
|
-
"success": true
|
279
|
+
"success": true,
|
280
|
+
"_links": {
|
281
|
+
"self": {
|
282
|
+
"href": "http://result"
|
283
|
+
}
|
284
|
+
}
|
275
285
|
},
|
276
286
|
"pact": {
|
277
287
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
@@ -321,7 +331,12 @@
|
|
321
331
|
},
|
322
332
|
"verificationResult": {
|
323
333
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
324
|
-
"success": true
|
334
|
+
"success": true,
|
335
|
+
"_links": {
|
336
|
+
"self": {
|
337
|
+
"href": "http://result"
|
338
|
+
}
|
339
|
+
}
|
325
340
|
},
|
326
341
|
"pact": {
|
327
342
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
@@ -418,7 +433,12 @@
|
|
418
433
|
},
|
419
434
|
"verificationResult": {
|
420
435
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
421
|
-
"success": true
|
436
|
+
"success": true,
|
437
|
+
"_links": {
|
438
|
+
"self": {
|
439
|
+
"href": "http://result"
|
440
|
+
}
|
441
|
+
}
|
422
442
|
},
|
423
443
|
"pact": {
|
424
444
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
@@ -439,7 +459,12 @@
|
|
439
459
|
},
|
440
460
|
"verificationResult": {
|
441
461
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
442
|
-
"success": true
|
462
|
+
"success": true,
|
463
|
+
"_links": {
|
464
|
+
"self": {
|
465
|
+
"href": "http://result"
|
466
|
+
}
|
467
|
+
}
|
443
468
|
},
|
444
469
|
"pact": {
|
445
470
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
@@ -492,7 +517,12 @@
|
|
492
517
|
},
|
493
518
|
"verificationResult": {
|
494
519
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
495
|
-
"success": true
|
520
|
+
"success": true,
|
521
|
+
"_links": {
|
522
|
+
"self": {
|
523
|
+
"href": "http://result"
|
524
|
+
}
|
525
|
+
}
|
496
526
|
},
|
497
527
|
"pact": {
|
498
528
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
@@ -542,7 +572,12 @@
|
|
542
572
|
},
|
543
573
|
"verificationResult": {
|
544
574
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
545
|
-
"success": true
|
575
|
+
"success": true,
|
576
|
+
"_links": {
|
577
|
+
"self": {
|
578
|
+
"href": "http://result"
|
579
|
+
}
|
580
|
+
}
|
546
581
|
},
|
547
582
|
"pact": {
|
548
583
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
@@ -592,7 +627,12 @@
|
|
592
627
|
},
|
593
628
|
"verificationResult": {
|
594
629
|
"verifiedAt": "2017-10-10T12:49:04+11:00",
|
595
|
-
"success": true
|
630
|
+
"success": true,
|
631
|
+
"_links": {
|
632
|
+
"self": {
|
633
|
+
"href": "http://result"
|
634
|
+
}
|
635
|
+
}
|
596
636
|
},
|
597
637
|
"pact": {
|
598
638
|
"createdAt": "2017-10-10T12:49:04+11:00"
|
data/spec/support/matrix.json
CHANGED
data/spec/support/matrix.txt
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
CONSUMER | C.VERSION | PROVIDER | P.VERSION | SUCCESS?
|
2
|
-
|
3
|
-
Foo | 4 | Bar | 5 | true
|
1
|
+
CONSUMER | C.VERSION | PROVIDER | P.VERSION | SUCCESS? | RESULT#
|
2
|
+
---------|-----------|----------|-----------|----------|--------
|
3
|
+
Foo | 4 | Bar | 5 | true | 1
|
@@ -1,3 +1,3 @@
|
|
1
|
-
CONSUMER | C.VERSION | PROVIDER | P.VERSION | SUCCESS?
|
2
|
-
|
3
|
-
??? | ??? | ??? | ??? | ???
|
1
|
+
CONSUMER | C.VERSION | PROVIDER | P.VERSION | SUCCESS? | RESULT#
|
2
|
+
---------|-----------|----------|-----------|----------|--------
|
3
|
+
??? | ??? | ??? | ??? | ??? |
|
@@ -0,0 +1,10 @@
|
|
1
|
+
CONSUMER | C.VERSION | PROVIDER | P.VERSION | SUCCESS? | RESULT#
|
2
|
+
---------|-----------|----------|-----------|----------|--------
|
3
|
+
Foo | 4 | Bar | 5 | true | 1
|
4
|
+
Foo | 4 | Bar | 5 | ??? |
|
5
|
+
Foo | 4 | Bar | 5 | false | 2
|
6
|
+
|
7
|
+
VERIFICATION RESULTS
|
8
|
+
--------------------
|
9
|
+
1. http://result (success)
|
10
|
+
2. http://result (failure)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pact_broker-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.35.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Beth Skurrie
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -56,16 +56,22 @@ dependencies:
|
|
56
56
|
name: thor
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0.20'
|
62
|
+
- - "<"
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '2.0'
|
62
65
|
type: :runtime
|
63
66
|
prerelease: false
|
64
67
|
version_requirements: !ruby/object:Gem::Requirement
|
65
68
|
requirements:
|
66
|
-
- - "
|
69
|
+
- - ">="
|
67
70
|
- !ruby/object:Gem::Version
|
68
71
|
version: '0.20'
|
72
|
+
- - "<"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '2.0'
|
69
75
|
- !ruby/object:Gem::Dependency
|
70
76
|
name: rake
|
71
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +86,20 @@ dependencies:
|
|
80
86
|
- - "~>"
|
81
87
|
- !ruby/object:Gem::Version
|
82
88
|
version: '13.0'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: dig_rb
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '1.0'
|
96
|
+
type: :runtime
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '1.0'
|
83
103
|
- !ruby/object:Gem::Dependency
|
84
104
|
name: fakefs
|
85
105
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,6 +156,20 @@ dependencies:
|
|
136
156
|
- - "~>"
|
137
157
|
- !ruby/object:Gem::Version
|
138
158
|
version: '1.16'
|
159
|
+
- !ruby/object:Gem::Dependency
|
160
|
+
name: pact-support
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - '='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 1.15.0
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - '='
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: 1.15.0
|
139
173
|
description: Client for the Pact Broker. Publish, retrieve and query pacts and verification
|
140
174
|
results.
|
141
175
|
email:
|
@@ -146,10 +180,10 @@ extensions: []
|
|
146
180
|
extra_rdoc_files: []
|
147
181
|
files:
|
148
182
|
- ".github/workflows/release_gem.yml"
|
183
|
+
- ".github/workflows/test.yml"
|
149
184
|
- ".github/workflows/trigger_pact_docs_update.yml"
|
150
185
|
- ".gitignore"
|
151
186
|
- ".rspec"
|
152
|
-
- ".travis.yml"
|
153
187
|
- CHANGELOG.md
|
154
188
|
- Dockerfile
|
155
189
|
- Gemfile
|
@@ -271,6 +305,7 @@ files:
|
|
271
305
|
- spec/support/matrix.json
|
272
306
|
- spec/support/matrix.txt
|
273
307
|
- spec/support/matrix_error.txt
|
308
|
+
- spec/support/matrix_with_results.txt
|
274
309
|
- spec/support/pacticipant_get.json
|
275
310
|
- spec/support/pacticipants_list.json
|
276
311
|
- spec/support/pacts_latest_list.json
|
@@ -295,7 +330,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
295
330
|
- !ruby/object:Gem::Version
|
296
331
|
version: '0'
|
297
332
|
requirements: []
|
298
|
-
rubygems_version: 3.
|
333
|
+
rubygems_version: 3.2.6
|
299
334
|
signing_key:
|
300
335
|
specification_version: 4
|
301
336
|
summary: See description
|
@@ -350,6 +385,7 @@ test_files:
|
|
350
385
|
- spec/support/matrix.json
|
351
386
|
- spec/support/matrix.txt
|
352
387
|
- spec/support/matrix_error.txt
|
388
|
+
- spec/support/matrix_with_results.txt
|
353
389
|
- spec/support/pacticipant_get.json
|
354
390
|
- spec/support/pacticipants_list.json
|
355
391
|
- spec/support/pacts_latest_list.json
|
data/.travis.yml
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
rvm:
|
3
|
-
- 2.2.4
|
4
|
-
- 2.4.1
|
5
|
-
|
6
|
-
# before_install:
|
7
|
-
# - (git show-ref | grep $(git log --pretty=%h -1) | sed 's|.*/\(.*\)|\1|' | sort -u | grep -v HEAD) || true
|
8
|
-
# - (git show -s --pretty=%d HEAD) || true
|
9
|
-
# - (git for-each-ref --format='%(objectname) %(refname:short)' refs/heads | awk "/^$(git rev-parse HEAD)/ {print \$2}") || true
|
10
|
-
# - (git show -s --pretty=%D HEAD | tr -s ', ' '\n' | grep -v HEAD | head -n1) || true
|
11
|
-
# - (git name-rev --name-only HEAD) || true
|