pact_broker 2.48.0 → 2.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/lib/pact_broker/api/resources/badge.rb +13 -4
- data/lib/pact_broker/api/resources/base_resource.rb +2 -2
- data/lib/pact_broker/api/resources/index.rb +5 -0
- data/lib/pact_broker/api/resources/webhook.rb +6 -4
- data/lib/pact_broker/api/resources/webhook_resource_methods.rb +2 -2
- data/lib/pact_broker/badges/service.rb +14 -7
- data/lib/pact_broker/config/setting.rb +5 -1
- data/lib/pact_broker/configuration.rb +4 -2
- data/lib/pact_broker/doc/controllers/app.rb +1 -0
- data/lib/pact_broker/doc/views/webhooks.markdown +8 -3
- data/lib/pact_broker/locale/en.yml +1 -0
- data/lib/pact_broker/pacts/selectors.rb +0 -1
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/webhooks/service.rb +13 -2
- data/spec/features/create_webhook_spec.rb +20 -35
- data/spec/features/delete_verification_spec.rb +0 -2
- data/spec/lib/pact_broker/api/resources/badge_spec.rb +39 -15
- data/spec/lib/pact_broker/api/resources/webhook_spec.rb +55 -12
- data/spec/lib/pact_broker/badges/service_spec.rb +20 -5
- data/spec/lib/pact_broker/config/load_spec.rb +7 -1
- data/spec/lib/pact_broker/config/save_spec.rb +9 -1
- data/spec/lib/pact_broker/pacts/build_verifiable_pact_notices_spec.rb +0 -1
- data/spec/lib/pact_broker/webhooks/service_spec.rb +30 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b99bf5d9f68ee92e651f20ad2595feb55060c1720a816179f1e143d7db4dea4
|
4
|
+
data.tar.gz: 174f33323d8ecb66ec0640705273b2629b4203812f1fa4f3d68a5c997db40328
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51835924b04c884319fcc89dcc729a572645ad490245d94eb77e3b7fd58df244d4980aaeb8363f10af52fae7ea8eeeb8a96096b4f6f8f711fc86ebbc30d097e9
|
7
|
+
data.tar.gz: d9a90fecfc31add0cfb0104eae721d55e2fb695823bbd151d12f4c9f8fdb1581ced85f679be6e489a05882bc9b04c3f448e97495e538afc98d8623ce08746050
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
<a name="v2.49.0"></a>
|
2
|
+
### v2.49.0 (2020-02-13)
|
3
|
+
|
4
|
+
|
5
|
+
#### Features
|
6
|
+
|
7
|
+
* **webhooks**
|
8
|
+
* support upsert of webhook via a PUT to /webhooks/{uuid} ([f9ba9ab5](/../../commit/f9ba9ab5))
|
9
|
+
|
10
|
+
* don't double parse the incoming JSON body when checking if it is invalid. ([bd74b82c](/../../commit/bd74b82c))
|
11
|
+
* support saving symbol configuration settings ([73db9c2b](/../../commit/73db9c2b))
|
12
|
+
* allow verification status badges to be served via a redirect instead of proxying the response ([a34d5f7f](/../../commit/a34d5f7f))
|
13
|
+
|
14
|
+
|
1
15
|
<a name="v2.48.0"></a>
|
2
16
|
### v2.48.0 (2020-02-07)
|
3
17
|
|
@@ -5,11 +5,10 @@ require 'pact_broker/configuration'
|
|
5
5
|
module PactBroker
|
6
6
|
module Api
|
7
7
|
module Resources
|
8
|
-
|
9
8
|
class Badge < BaseResource
|
10
9
|
|
11
10
|
def allowed_methods
|
12
|
-
["GET", "OPTIONS"
|
11
|
+
["GET", "OPTIONS"]
|
13
12
|
end
|
14
13
|
|
15
14
|
def content_types_provided
|
@@ -17,6 +16,11 @@ module PactBroker
|
|
17
16
|
end
|
18
17
|
|
19
18
|
def resource_exists?
|
19
|
+
!badge_service.can_provide_badge_using_redirect?
|
20
|
+
end
|
21
|
+
|
22
|
+
# Only called if resource_exists? returns false
|
23
|
+
def previously_existed?
|
20
24
|
true
|
21
25
|
end
|
22
26
|
|
@@ -28,13 +32,18 @@ module PactBroker
|
|
28
32
|
false
|
29
33
|
end
|
30
34
|
|
31
|
-
private
|
32
|
-
|
33
35
|
def to_svg
|
34
36
|
response.headers['Cache-Control'] = 'no-cache'
|
35
37
|
comment + badge_service.pact_verification_badge(pact, label, initials, pseudo_branch_verification_status)
|
36
38
|
end
|
37
39
|
|
40
|
+
def moved_temporarily?
|
41
|
+
response.headers['Cache-Control'] = 'no-cache'
|
42
|
+
badge_service.pact_verification_badge_url(pact, label, initials, pseudo_branch_verification_status)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
38
47
|
def pact
|
39
48
|
@pact ||= pact_service.find_latest_pact(identifier_from_path)
|
40
49
|
end
|
@@ -84,7 +84,7 @@ module PactBroker
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def params
|
87
|
-
@params ||= JSON.parse(request.body.to_s, {symbolize_names: true}.merge(PACT_PARSING_OPTIONS))
|
87
|
+
@params ||= JSON.parse(request.body.to_s, { symbolize_names: true }.merge(PACT_PARSING_OPTIONS)) #Not load! Otherwise it will try to load Ruby classes.
|
88
88
|
end
|
89
89
|
|
90
90
|
def params_with_string_keys
|
@@ -123,7 +123,7 @@ module PactBroker
|
|
123
123
|
|
124
124
|
def invalid_json?
|
125
125
|
begin
|
126
|
-
|
126
|
+
params
|
127
127
|
false
|
128
128
|
rescue StandardError => e
|
129
129
|
logger.info "Error parsing JSON #{e} - #{request_body}"
|
@@ -94,6 +94,11 @@ module PactBroker
|
|
94
94
|
title: 'Webhooks',
|
95
95
|
templated: false
|
96
96
|
},
|
97
|
+
'pb:webhook' => {
|
98
|
+
href: base_url + '/webhooks/{uuid}',
|
99
|
+
title: 'Webhook',
|
100
|
+
templated: true
|
101
|
+
},
|
97
102
|
'pb:integrations' => {
|
98
103
|
href: base_url + '/integrations',
|
99
104
|
title: 'Integrations',
|
@@ -28,7 +28,7 @@ module PactBroker
|
|
28
28
|
|
29
29
|
def malformed_request?
|
30
30
|
if request.put?
|
31
|
-
return invalid_json? || webhook_validation_errors?(
|
31
|
+
return invalid_json? || webhook_validation_errors?(parsed_webhook, uuid)
|
32
32
|
end
|
33
33
|
false
|
34
34
|
end
|
@@ -38,7 +38,9 @@ module PactBroker
|
|
38
38
|
@webhook = webhook_service.update_by_uuid uuid, params_with_string_keys
|
39
39
|
response.body = to_json
|
40
40
|
else
|
41
|
-
|
41
|
+
@webhook = webhook_service.create(uuid, parsed_webhook, consumer, provider)
|
42
|
+
response.body = to_json
|
43
|
+
201
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
@@ -57,8 +59,8 @@ module PactBroker
|
|
57
59
|
@webhook ||= webhook_service.find_by_uuid uuid
|
58
60
|
end
|
59
61
|
|
60
|
-
def
|
61
|
-
@
|
62
|
+
def parsed_webhook
|
63
|
+
@parsed_webhook ||= Decorators::WebhookDecorator.new(PactBroker::Domain::Webhook.new).from_json(request_body)
|
62
64
|
end
|
63
65
|
|
64
66
|
def uuid
|
@@ -2,8 +2,8 @@ module PactBroker
|
|
2
2
|
module Api
|
3
3
|
module Resources
|
4
4
|
module WebhookResourceMethods
|
5
|
-
def webhook_validation_errors?
|
6
|
-
errors = webhook_service.errors(webhook)
|
5
|
+
def webhook_validation_errors?(webhook, uuid = nil)
|
6
|
+
errors = webhook_service.errors(webhook, uuid)
|
7
7
|
if !errors.empty?
|
8
8
|
set_json_validation_error_messages(errors.messages)
|
9
9
|
true
|
@@ -15,14 +15,21 @@ module PactBroker
|
|
15
15
|
SPACE_DASH_UNDERSCORE = /[\s_\-]/
|
16
16
|
CACHE = {}
|
17
17
|
|
18
|
+
def can_provide_badge_using_redirect?
|
19
|
+
PactBroker.configuration.badge_provider_mode == :redirect && !!PactBroker.configuration.shields_io_base_url
|
20
|
+
end
|
21
|
+
|
18
22
|
def pact_verification_badge pact, label, initials, pseudo_branch_verification_status
|
19
23
|
return static_svg(pact, pseudo_branch_verification_status) unless pact
|
20
24
|
|
21
|
-
|
22
|
-
|
23
|
-
color = badge_color pseudo_branch_verification_status
|
25
|
+
dynamic_svg(pact, label, initials, pseudo_branch_verification_status) || static_svg(pact, pseudo_branch_verification_status)
|
26
|
+
end
|
24
27
|
|
25
|
-
|
28
|
+
def pact_verification_badge_url(pact, label, initials, pseudo_branch_verification_status)
|
29
|
+
title = badge_title(pact, label, initials)
|
30
|
+
status = badge_status(pseudo_branch_verification_status)
|
31
|
+
color = badge_color(pseudo_branch_verification_status)
|
32
|
+
build_shield_io_uri(title, status, color)
|
26
33
|
end
|
27
34
|
|
28
35
|
def clear_cache
|
@@ -78,9 +85,9 @@ module PactBroker
|
|
78
85
|
end
|
79
86
|
end
|
80
87
|
|
81
|
-
def dynamic_svg
|
88
|
+
def dynamic_svg pact, label, initials, pseudo_branch_verification_status
|
82
89
|
return nil unless PactBroker.configuration.shields_io_base_url
|
83
|
-
uri =
|
90
|
+
uri = pact_verification_badge_url(pact, label, initials, pseudo_branch_verification_status)
|
84
91
|
begin
|
85
92
|
response = do_request(uri)
|
86
93
|
response.code == '200' ? response.body : nil
|
@@ -93,7 +100,7 @@ module PactBroker
|
|
93
100
|
end
|
94
101
|
end
|
95
102
|
|
96
|
-
def
|
103
|
+
def build_shield_io_uri left_text, right_text, color
|
97
104
|
shield_base_url = PactBroker.configuration.shields_io_base_url
|
98
105
|
path = "/badge/#{escape_text(left_text)}-#{escape_text(right_text)}-#{color}.svg"
|
99
106
|
URI.parse(shield_base_url + path)
|
@@ -14,6 +14,8 @@ module PactBroker
|
|
14
14
|
JSON.parse(value, symbolize_names: true)
|
15
15
|
when 'string'
|
16
16
|
value
|
17
|
+
when 'symbol'
|
18
|
+
value.to_sym
|
17
19
|
when 'integer'
|
18
20
|
Integer(value)
|
19
21
|
when 'float'
|
@@ -33,7 +35,7 @@ module PactBroker
|
|
33
35
|
"1"
|
34
36
|
when FalseClass
|
35
37
|
"0"
|
36
|
-
when SpaceDelimitedStringList
|
38
|
+
when SpaceDelimitedStringList, Symbol
|
37
39
|
object.to_s
|
38
40
|
when Array, Hash
|
39
41
|
object.to_json
|
@@ -56,6 +58,8 @@ module PactBroker
|
|
56
58
|
'integer'
|
57
59
|
when Float
|
58
60
|
'float'
|
61
|
+
when Symbol
|
62
|
+
'symbol'
|
59
63
|
else
|
60
64
|
nil
|
61
65
|
end
|
@@ -30,7 +30,8 @@ module PactBroker
|
|
30
30
|
:webhook_scheme_whitelist,
|
31
31
|
:webhook_host_whitelist,
|
32
32
|
:base_equality_only_on_content_that_affects_verification_results,
|
33
|
-
:seed_example_data
|
33
|
+
:seed_example_data,
|
34
|
+
:badge_provider_mode
|
34
35
|
]
|
35
36
|
|
36
37
|
attr_accessor :base_url, :log_dir, :database_connection, :auto_migrate_db, :auto_migrate_db_data, :example_data_seeder, :seed_example_data, :use_hal_browser, :html_pact_renderer, :use_rack_protection
|
@@ -40,7 +41,7 @@ module PactBroker
|
|
40
41
|
attr_accessor :webhook_retry_schedule
|
41
42
|
attr_reader :webhook_http_method_whitelist, :webhook_scheme_whitelist, :webhook_host_whitelist
|
42
43
|
attr_accessor :semver_formats
|
43
|
-
attr_accessor :enable_public_badge_access, :shields_io_base_url
|
44
|
+
attr_accessor :enable_public_badge_access, :shields_io_base_url, :badge_provider_mode
|
44
45
|
attr_accessor :disable_ssl_verification
|
45
46
|
attr_accessor :base_equality_only_on_content_that_affects_verification_results
|
46
47
|
attr_reader :api_error_reporters
|
@@ -69,6 +70,7 @@ module PactBroker
|
|
69
70
|
config.enable_diagnostic_endpoints = true
|
70
71
|
config.enable_public_badge_access = false # For security
|
71
72
|
config.shields_io_base_url = "https://img.shields.io".freeze
|
73
|
+
config.badge_provider_mode = :proxy # other option is :redirect
|
72
74
|
config.use_case_sensitive_resource_names = true
|
73
75
|
config.html_pact_renderer = default_html_pact_render
|
74
76
|
config.version_parser = PactBroker::Versions::ParseSemanticVersion
|
@@ -8,7 +8,7 @@ Allowed methods: `GET`, `POST`
|
|
8
8
|
|
9
9
|
*Individual resource*
|
10
10
|
|
11
|
-
Path: `/webhook/
|
11
|
+
Path: `/webhook/{uuid}`
|
12
12
|
|
13
13
|
Allowed methods: `GET`, `PUT`, `DELETE`
|
14
14
|
|
@@ -16,11 +16,16 @@ Webhooks are HTTP requests that are executed asynchronously after certain events
|
|
16
16
|
|
17
17
|
### Creating
|
18
18
|
|
19
|
-
To create a webhook, send a `POST` request to `/webhooks` with the body described below. You can do
|
19
|
+
To create a webhook, send a `POST` request to `/webhooks` with the body described below. You can also do a `PUT` to `/webhooks/{uuid}`, where the UUID is a identifier that you generate yourself. This supports upserting webhooks, allowing you to automate your Pact Broker set up.
|
20
|
+
|
21
|
+
The easiest way to create a webhook is by using the [Pact Broker Client CLI](https://github.com/pact-foundation/pact_broker-client/#create-webhook). It is available as a docker container and a standalone executable for all platforms.
|
22
|
+
|
23
|
+
You can also create webhooks through the API Browser by clicking on the `NON-GET` button for the `pb:webhooks` relation on the index, pasting in the JSON body, and clicking "Make Request".
|
20
24
|
|
21
25
|
Below is an example webhook to trigger a Bamboo job when any contract for the provider "Foo" has changed. Both provider and consumer are optional - omitting either indicates that any pacticipant in that role will be matched. Webhooks with neither provider nor consumer specified are "global" webhooks that will trigger for any consumer/provider pair.
|
22
26
|
|
23
27
|
{
|
28
|
+
"description": "Trigger SomeProject CI",
|
24
29
|
"provider": {
|
25
30
|
"name": "Bar"
|
26
31
|
},
|
@@ -90,6 +95,7 @@ To specify an XML body, you will need to use a correctly escaped string (or use
|
|
90
95
|
|
91
96
|
The following variables may be used in the request path, parameters or body, and will be replaced with their appropriate values at runtime.
|
92
97
|
|
98
|
+
* `${pactbroker.pactUrl}`: the "permalink" URL to the newly published pact (the URL specifying the consumer version URL, rather than the "/latest" format.)
|
93
99
|
* `${pactbroker.consumerName}`: the consumer name
|
94
100
|
* `${pactbroker.providerName}`: the provider name
|
95
101
|
* `${pactbroker.consumerVersionNumber}`: the version number of the most recent consumer version associated with the pact content.
|
@@ -100,7 +106,6 @@ The following variables may be used in the request path, parameters or body, and
|
|
100
106
|
* `${pactbroker.providerLabels}`: the list of labels for the provider associated with the pact content, separated by ", ".
|
101
107
|
* `${pactbroker.githubVerificationStatus}`: the verification status using the correct keywords for posting to the the [Github commit status API](https://developer.github.com/v3/repos/statuses).
|
102
108
|
* `${pactbroker.bitbucketVerificationStatus}`: the verification status using the correct keywords for posting to the the [Bitbucket commit status API](https://developer.atlassian.com/server/bitbucket/how-tos/updating-build-status-for-commits/).
|
103
|
-
* `${pactbroker.pactUrl}`: the "permalink" URL to the newly published pact (the URL specifying the consumer version URL, rather than the "/latest" format.)
|
104
109
|
* `${pactbroker.verificationResultUrl}`: the URL to the relevant verification result.
|
105
110
|
|
106
111
|
Example usage:
|
@@ -43,6 +43,7 @@ en:
|
|
43
43
|
consumer_version_number_invalid: "Consumer version number '%{consumer_version_number}' cannot be parsed to a version number. The expected format (unless this configuration has been overridden) is a semantic version. eg. 1.3.0 or 2.0.4.rc1"
|
44
44
|
pacticipant_name_mismatch: "in pact ('%{name_in_pact}') does not match %{pacticipant} name in path ('%{name}')."
|
45
45
|
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"
|
46
|
+
invalid_webhook_uuid: The UUID can only contain the characters A-Z, a-z, 0-9, _ and -, and must be 16 or more characters.
|
46
47
|
duplicate_pacticipant: |
|
47
48
|
This is the first time a pact has been published for "%{new_name}".
|
48
49
|
The name "%{new_name}" is very similar to the following existing consumers/providers:
|
data/lib/pact_broker/version.rb
CHANGED
@@ -14,6 +14,7 @@ require 'pact_broker/hash_refinements'
|
|
14
14
|
require 'pact_broker/webhooks/execution_configuration'
|
15
15
|
require 'pact_broker/messages'
|
16
16
|
require 'pact_broker/webhooks/pact_and_verification_parameters'
|
17
|
+
require 'reform/contract/errors'
|
17
18
|
|
18
19
|
module PactBroker
|
19
20
|
module Webhooks
|
@@ -28,14 +29,24 @@ module PactBroker
|
|
28
29
|
include Logging
|
29
30
|
extend PactBroker::Messages
|
30
31
|
|
32
|
+
# Not actually a UUID. Ah well.
|
33
|
+
def self.valid_uuid_format?(uuid)
|
34
|
+
!!(uuid =~ /^[A-Za-z0-9_\-]{16,}$/)
|
35
|
+
end
|
36
|
+
|
31
37
|
def self.next_uuid
|
32
38
|
SecureRandom.urlsafe_base64
|
33
39
|
end
|
34
40
|
|
35
|
-
def self.errors webhook
|
41
|
+
def self.errors webhook, uuid = nil
|
36
42
|
contract = PactBroker::Api::Contracts::WebhookContract.new(webhook)
|
37
43
|
contract.validate(webhook.attributes)
|
38
|
-
contract.errors
|
44
|
+
errors = contract.errors
|
45
|
+
|
46
|
+
if uuid && !valid_uuid_format?(uuid)
|
47
|
+
errors.add("uuid", message("errors.validation.invalid_webhook_uuid"))
|
48
|
+
end
|
49
|
+
errors
|
39
50
|
end
|
40
51
|
|
41
52
|
def self.create uuid, webhook, consumer, provider
|
@@ -1,13 +1,10 @@
|
|
1
|
-
require 'support/test_data_builder'
|
2
|
-
|
3
1
|
describe "Creating a webhook" do
|
4
|
-
|
5
2
|
before do
|
6
|
-
|
3
|
+
td.create_pact_with_hierarchy("Some Consumer", "1", "Some Provider")
|
7
4
|
end
|
8
5
|
|
9
6
|
let(:headers) { {'CONTENT_TYPE' => 'application/json'} }
|
10
|
-
let(:response_body) { JSON.parse(
|
7
|
+
let(:response_body) { JSON.parse(subject.body, symbolize_names: true)}
|
11
8
|
let(:webhook_json) { webhook_hash.to_json }
|
12
9
|
let(:webhook_hash) do
|
13
10
|
{
|
@@ -37,40 +34,29 @@ describe "Creating a webhook" do
|
|
37
34
|
context "with invalid attributes" do
|
38
35
|
let(:webhook_hash) { {} }
|
39
36
|
|
40
|
-
|
41
|
-
subject
|
42
|
-
expect(last_response.status).to be 400
|
43
|
-
end
|
37
|
+
its(:status) { is_expected.to be 400 }
|
44
38
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
39
|
+
it "returns a JSON content type" do
|
40
|
+
expect(subject.headers['Content-Type']).to eq 'application/hal+json;charset=utf-8'
|
41
|
+
end
|
49
42
|
|
50
43
|
it "returns the validation errors" do
|
51
|
-
subject
|
52
44
|
expect(response_body[:errors]).to_not be_empty
|
53
45
|
end
|
54
46
|
end
|
55
47
|
|
56
48
|
context "with valid attributes" do
|
57
|
-
|
58
|
-
subject
|
59
|
-
expect(last_response.status).to be 201
|
60
|
-
end
|
49
|
+
its(:status) { is_expected.to be 201 }
|
61
50
|
|
62
51
|
it "returns the Location header" do
|
63
|
-
subject
|
64
|
-
expect(last_response.headers['Location']).to match(%r{http://example.org/webhooks/.+})
|
52
|
+
expect(subject.headers['Location']).to match(%r{http://example.org/webhooks/.+})
|
65
53
|
end
|
66
54
|
|
67
55
|
it "returns a JSON Content Type" do
|
68
|
-
subject
|
69
|
-
expect(last_response.headers['Content-Type']).to eq 'application/hal+json;charset=utf-8'
|
56
|
+
expect(subject.headers['Content-Type']).to eq 'application/hal+json;charset=utf-8'
|
70
57
|
end
|
71
58
|
|
72
59
|
it "returns the newly created webhook" do
|
73
|
-
subject
|
74
60
|
expect(response_body).to include webhook_hash
|
75
61
|
end
|
76
62
|
end
|
@@ -83,10 +69,7 @@ describe "Creating a webhook" do
|
|
83
69
|
webhook_hash[:provider] = { name: "Some Provider" }
|
84
70
|
end
|
85
71
|
|
86
|
-
|
87
|
-
subject
|
88
|
-
expect(last_response.status).to be 201
|
89
|
-
end
|
72
|
+
its(:status) { is_expected.to be 201 }
|
90
73
|
|
91
74
|
it "creates a webhook without a consumer" do
|
92
75
|
subject
|
@@ -101,10 +84,7 @@ describe "Creating a webhook" do
|
|
101
84
|
webhook_hash[:consumer] = { name: "Some Consumer" }
|
102
85
|
end
|
103
86
|
|
104
|
-
|
105
|
-
subject
|
106
|
-
expect(last_response.status).to be 201
|
107
|
-
end
|
87
|
+
its(:status) { is_expected.to be 201 }
|
108
88
|
|
109
89
|
it "creates a webhook without a provider" do
|
110
90
|
subject
|
@@ -116,10 +96,7 @@ describe "Creating a webhook" do
|
|
116
96
|
context "with no consumer or provider" do
|
117
97
|
let(:path) { "/webhooks" }
|
118
98
|
|
119
|
-
|
120
|
-
subject
|
121
|
-
expect(last_response.status).to be 201
|
122
|
-
end
|
99
|
+
its(:status) { is_expected.to be 201 }
|
123
100
|
|
124
101
|
it "creates a webhook without a provider" do
|
125
102
|
subject
|
@@ -127,4 +104,12 @@ describe "Creating a webhook" do
|
|
127
104
|
expect(PactBroker::Webhooks::Webhook.first.provider).to be nil
|
128
105
|
end
|
129
106
|
end
|
107
|
+
|
108
|
+
context "with a UUID" do
|
109
|
+
let(:path) { "/webhooks/1234123412341234" }
|
110
|
+
|
111
|
+
subject { put(path, webhook_json, headers) }
|
112
|
+
|
113
|
+
its(:status) { is_expected.to be 201 }
|
114
|
+
end
|
130
115
|
end
|
@@ -13,7 +13,9 @@ module PactBroker
|
|
13
13
|
allow(PactBroker::Pacts::Service).to receive(:find_latest_pact).and_return(pact)
|
14
14
|
allow(PactBroker::Verifications::Service).to receive(:find_latest_verification_for).and_return(verification)
|
15
15
|
allow(PactBroker::Badges::Service).to receive(:pact_verification_badge).and_return("badge")
|
16
|
+
allow(PactBroker::Badges::Service).to receive(:pact_verification_badge_url).and_return("http://badge")
|
16
17
|
allow(PactBroker::Verifications::PseudoBranchStatus).to receive(:new).and_return(pseudo_branch_verification_status)
|
18
|
+
allow(PactBroker::Badges::Service).to receive(:can_provide_badge_using_redirect?).and_return(false)
|
17
19
|
end
|
18
20
|
|
19
21
|
let(:pact) { instance_double("PactBroker::Domain::Pact", consumer: consumer, provider: provider, consumer_version_number: "2", revision_number: "1") }
|
@@ -47,7 +49,6 @@ module PactBroker
|
|
47
49
|
end
|
48
50
|
|
49
51
|
context "when enable_public_badge_access is true" do
|
50
|
-
|
51
52
|
before do
|
52
53
|
PactBroker.configuration.enable_public_badge_access = true
|
53
54
|
end
|
@@ -67,25 +68,48 @@ module PactBroker
|
|
67
68
|
subject
|
68
69
|
end
|
69
70
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
71
|
+
context "when can_provide_badge_using_redirect? is false" do
|
72
|
+
before do
|
73
|
+
allow(PactBroker::Badges::Service).to receive(:can_provide_badge_using_redirect?).and_return(false)
|
74
|
+
end
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
|
76
|
+
it "creates a badge" do
|
77
|
+
expect(PactBroker::Badges::Service).to receive(:pact_verification_badge).with(pact, nil, false, :verified)
|
78
|
+
subject
|
79
|
+
end
|
78
80
|
|
79
|
-
|
80
|
-
|
81
|
-
|
81
|
+
it "returns a 200 status" do
|
82
|
+
expect(subject.status).to eq 200
|
83
|
+
end
|
82
84
|
|
83
|
-
|
84
|
-
|
85
|
+
it "does not allow caching" do
|
86
|
+
expect(subject.headers['Cache-Control']).to eq 'no-cache'
|
87
|
+
end
|
88
|
+
|
89
|
+
it "returns the badge" do
|
90
|
+
expect(subject.body).to end_with "badge"
|
91
|
+
end
|
92
|
+
|
93
|
+
it "returns a comment with the consumer and provider numbers" do
|
94
|
+
expect(subject.body).to include "<!-- consumer version 2 revision 1 provider version 3 number 7 -->"
|
95
|
+
end
|
85
96
|
end
|
86
97
|
|
87
|
-
|
88
|
-
|
98
|
+
context "when can_provide_badge_using_redirect? is true" do
|
99
|
+
before do
|
100
|
+
allow(PactBroker::Badges::Service).to receive(:can_provide_badge_using_redirect?).and_return(true)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "determines the URL of the badge to redirect to" do
|
104
|
+
expect(PactBroker::Badges::Service).to receive(:pact_verification_badge_url).with(pact, nil, false, :verified)
|
105
|
+
subject
|
106
|
+
end
|
107
|
+
|
108
|
+
it "returns a 301 redirect to the badge URL" do
|
109
|
+
expect(subject.status).to eq 307
|
110
|
+
expect(subject.headers['Location']).to eq 'http://badge'
|
111
|
+
expect(subject.headers['Cache-Control']).to eq 'no-cache'
|
112
|
+
end
|
89
113
|
end
|
90
114
|
|
91
115
|
context "when the label param is specified" do
|
@@ -2,11 +2,8 @@ require 'spec_helper'
|
|
2
2
|
require 'pact_broker/api/resources/webhook'
|
3
3
|
|
4
4
|
module PactBroker::Api
|
5
|
-
|
6
5
|
module Resources
|
7
|
-
|
8
6
|
describe Webhook do
|
9
|
-
|
10
7
|
before do
|
11
8
|
allow(PactBroker::Webhooks::Service).to receive(:find_by_uuid).and_return(webhook)
|
12
9
|
end
|
@@ -23,15 +20,14 @@ module PactBroker::Api
|
|
23
20
|
end
|
24
21
|
|
25
22
|
context "when the webhook exists" do
|
23
|
+
before do
|
24
|
+
allow(Decorators::WebhookDecorator).to receive(:new).and_return(decorator)
|
25
|
+
end
|
26
26
|
|
27
27
|
let(:webhook) { double("webhook") }
|
28
28
|
let(:decorator) { double(Decorators::WebhookDecorator, to_json: json)}
|
29
29
|
let(:json) { {some: 'json'}.to_json }
|
30
30
|
|
31
|
-
before do
|
32
|
-
allow(Decorators::WebhookDecorator).to receive(:new).and_return(decorator)
|
33
|
-
end
|
34
|
-
|
35
31
|
it "finds the webhook by UUID" do
|
36
32
|
expect(PactBroker::Webhooks::Service).to receive(:find_by_uuid).with('some-uuid')
|
37
33
|
subject
|
@@ -56,14 +52,61 @@ module PactBroker::Api
|
|
56
52
|
end
|
57
53
|
|
58
54
|
describe "PUT" do
|
55
|
+
before do
|
56
|
+
allow(Decorators::WebhookDecorator).to receive(:new).and_return(decorator)
|
57
|
+
allow(PactBroker::Webhooks::Service).to receive(:create).and_return(created_webhook)
|
58
|
+
allow_any_instance_of(Webhook).to receive(:consumer).and_return(consumer)
|
59
|
+
allow_any_instance_of(Webhook).to receive(:provider).and_return(provider)
|
60
|
+
allow_any_instance_of(Webhook).to receive(:webhook_validation_errors?).and_return(false)
|
61
|
+
end
|
62
|
+
|
63
|
+
let(:consumer) { double('consumer') }
|
64
|
+
let(:provider) { double('provider') }
|
65
|
+
let(:webhook) { double("webhook") }
|
66
|
+
let(:decorator) { double(Decorators::WebhookDecorator, from_json: parsed_webhook, to_json: json)}
|
67
|
+
let(:json) { {some: 'json'}.to_json }
|
68
|
+
|
69
|
+
let(:parsed_webhook) { double('parsed_webhook') }
|
70
|
+
let(:created_webhook) { double('created_webhook') }
|
71
|
+
let(:webhook) { nil }
|
72
|
+
let(:webhook_json) { load_fixture('webhook_valid.json') }
|
73
|
+
let(:uuid) { 'some-uuid' }
|
74
|
+
|
75
|
+
subject { put("/webhooks/#{uuid}", webhook_json, 'CONTENT_TYPE' => 'application/json') }
|
76
|
+
|
77
|
+
it "validates the UUID" do
|
78
|
+
expect_any_instance_of(Webhook).to receive(:webhook_validation_errors?).with(parsed_webhook, uuid)
|
79
|
+
subject
|
80
|
+
end
|
81
|
+
|
59
82
|
context "when the webhook does not exist" do
|
60
|
-
|
61
|
-
|
83
|
+
it "creates the webhook" do
|
84
|
+
expect(PactBroker::Webhooks::Service).to receive(:create).with(uuid, parsed_webhook, consumer, provider)
|
85
|
+
subject
|
86
|
+
end
|
62
87
|
|
63
|
-
|
88
|
+
its(:status) { is_expected.to eq 201 }
|
64
89
|
|
65
|
-
it "returns
|
66
|
-
expect(subject).to
|
90
|
+
it "returns the JSON respresentation of the webhook" do
|
91
|
+
expect(subject.body).to eq json
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "when the webhook does exist" do
|
96
|
+
before do
|
97
|
+
allow(PactBroker::Webhooks::Service).to receive(:update_by_uuid).and_return(created_webhook)
|
98
|
+
end
|
99
|
+
let(:webhook) { double('existing webhook') }
|
100
|
+
|
101
|
+
its(:status) { is_expected.to eq 200 }
|
102
|
+
|
103
|
+
it "updates the webhook" do
|
104
|
+
expect(PactBroker::Webhooks::Service).to receive(:update_by_uuid).with(uuid, JSON.parse(webhook_json))
|
105
|
+
subject
|
106
|
+
end
|
107
|
+
|
108
|
+
it "returns the JSON respresentation of the webhook" do
|
109
|
+
expect(subject.body).to eq json
|
67
110
|
end
|
68
111
|
end
|
69
112
|
end
|
@@ -14,7 +14,7 @@ module PactBroker
|
|
14
14
|
let(:expected_url) { "https://img.shields.io/badge/#{expected_left_text}-#{expected_right_text}-#{expected_color}.svg" }
|
15
15
|
let(:expected_color) { "brightgreen" }
|
16
16
|
let(:expected_right_text) { "verified" }
|
17
|
-
let(:expected_left_text) { "foo--bar%
|
17
|
+
let(:expected_left_text) { "foo--bar%2fthing__blah%20pact" }
|
18
18
|
let(:response_status) { 200 }
|
19
19
|
let!(:http_request) do
|
20
20
|
stub_request(:get, expected_url).to_return(:status => response_status, :body => "svg")
|
@@ -22,6 +22,8 @@ module PactBroker
|
|
22
22
|
|
23
23
|
subject { PactBroker::Badges::Service.pact_verification_badge pact, label, initials, pseudo_branch_verification_status }
|
24
24
|
|
25
|
+
let(:pact_verification_badge_url) { PactBroker::Badges::Service.pact_verification_badge_url(pact, label, initials, pseudo_branch_verification_status) }
|
26
|
+
|
25
27
|
before do
|
26
28
|
Service.clear_cache
|
27
29
|
allow(Service).to receive(:logger).and_return(logger)
|
@@ -41,48 +43,53 @@ module PactBroker
|
|
41
43
|
it "creates a badge with the consumer and provider names" do
|
42
44
|
subject
|
43
45
|
expect(http_request).to have_been_made
|
46
|
+
expect(pact_verification_badge_url).to eq URI(expected_url)
|
44
47
|
end
|
45
48
|
|
46
49
|
context "when initials is true" do
|
47
|
-
let(:expected_left_text) { "fb%
|
50
|
+
let(:expected_left_text) { "fb%2ftb%20pact" }
|
48
51
|
let(:initials) { true }
|
49
52
|
|
50
53
|
it "creates a badge with the consumer and provider initials" do
|
51
54
|
subject
|
52
55
|
expect(http_request).to have_been_made
|
56
|
+
expect(pact_verification_badge_url).to eq URI(expected_url)
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
56
60
|
context "when initials is true but the consumer and provider names only contain one word" do
|
57
|
-
let(:expected_left_text) { "foo%
|
61
|
+
let(:expected_left_text) { "foo%2fbar%20pact" }
|
58
62
|
let(:initials) { true }
|
59
63
|
let(:pact) { double("pact", consumer_name: "Foo", provider_name: "Bar") }
|
60
64
|
|
61
65
|
it "creates a badge with the consumer and provider names, not initials" do
|
62
66
|
subject
|
63
67
|
expect(http_request).to have_been_made
|
68
|
+
expect(pact_verification_badge_url).to eq URI(expected_url)
|
64
69
|
end
|
65
70
|
end
|
66
71
|
|
67
72
|
context "when initials is true but the consumer and provider names are one camel cased word" do
|
68
|
-
let(:expected_left_text) { "fa%
|
73
|
+
let(:expected_left_text) { "fa%2fbp%20pact" }
|
69
74
|
let(:initials) { true }
|
70
75
|
let(:pact) { double("pact", consumer_name: "FooApp", provider_name: "barProvider") }
|
71
76
|
|
72
77
|
it "creates a badge with the consumer and provider names, not initials" do
|
73
78
|
subject
|
74
79
|
expect(http_request).to have_been_made
|
80
|
+
expect(pact_verification_badge_url).to eq URI(expected_url)
|
75
81
|
end
|
76
82
|
end
|
77
83
|
|
78
84
|
context "when initials is true but the consumer and provider names are one camel cased word" do
|
79
|
-
let(:expected_left_text) { "fa%
|
85
|
+
let(:expected_left_text) { "fa%2fdat%20pact" }
|
80
86
|
let(:initials) { true }
|
81
87
|
let(:pact) { double("pact", consumer_name: "FooApp", provider_name: "doAThing") }
|
82
88
|
|
83
89
|
it "creates a badge with the consumer and provider names, not initials" do
|
84
90
|
subject
|
85
91
|
expect(http_request).to have_been_made
|
92
|
+
expect(pact_verification_badge_url).to eq URI(expected_url)
|
86
93
|
end
|
87
94
|
end
|
88
95
|
end
|
@@ -94,6 +101,7 @@ module PactBroker
|
|
94
101
|
it "creates a badge with only the consumer name" do
|
95
102
|
subject
|
96
103
|
expect(http_request).to have_been_made
|
104
|
+
expect(pact_verification_badge_url).to eq URI(expected_url)
|
97
105
|
end
|
98
106
|
|
99
107
|
context "when initials is true" do
|
@@ -103,6 +111,7 @@ module PactBroker
|
|
103
111
|
it "creates a badge with only the consumer initials" do
|
104
112
|
subject
|
105
113
|
expect(http_request).to have_been_made
|
114
|
+
expect(pact_verification_badge_url).to eq URI(expected_url)
|
106
115
|
end
|
107
116
|
end
|
108
117
|
end
|
@@ -114,6 +123,7 @@ module PactBroker
|
|
114
123
|
it "creates a badge with only the provider name" do
|
115
124
|
subject
|
116
125
|
expect(http_request).to have_been_made
|
126
|
+
expect(pact_verification_badge_url).to eq URI(expected_url)
|
117
127
|
end
|
118
128
|
|
119
129
|
context "when initials is true" do
|
@@ -123,6 +133,7 @@ module PactBroker
|
|
123
133
|
it "creates a badge with only the provider initials" do
|
124
134
|
subject
|
125
135
|
expect(http_request).to have_been_made
|
136
|
+
expect(pact_verification_badge_url).to eq URI(expected_url)
|
126
137
|
end
|
127
138
|
end
|
128
139
|
end
|
@@ -131,6 +142,7 @@ module PactBroker
|
|
131
142
|
it "create a green badge with left text 'verified'" do
|
132
143
|
subject
|
133
144
|
expect(http_request).to have_been_made
|
145
|
+
expect(pact_verification_badge_url).to eq URI(expected_url)
|
134
146
|
end
|
135
147
|
end
|
136
148
|
|
@@ -142,6 +154,7 @@ module PactBroker
|
|
142
154
|
it "create a lightgrey badge with left text 'unknown'" do
|
143
155
|
subject
|
144
156
|
expect(http_request).to have_been_made
|
157
|
+
expect(pact_verification_badge_url).to eq URI(expected_url)
|
145
158
|
end
|
146
159
|
end
|
147
160
|
|
@@ -153,6 +166,7 @@ module PactBroker
|
|
153
166
|
it "create a red badge with left text 'failed'" do
|
154
167
|
subject
|
155
168
|
expect(http_request).to have_been_made
|
169
|
+
expect(pact_verification_badge_url).to eq URI(expected_url)
|
156
170
|
end
|
157
171
|
end
|
158
172
|
|
@@ -164,6 +178,7 @@ module PactBroker
|
|
164
178
|
it "create a orange badge with left text 'changed'" do
|
165
179
|
subject
|
166
180
|
expect(http_request).to have_been_made
|
181
|
+
expect(pact_verification_badge_url).to eq URI(expected_url)
|
167
182
|
end
|
168
183
|
end
|
169
184
|
|
@@ -7,7 +7,7 @@ module PactBroker
|
|
7
7
|
describe ".call" do
|
8
8
|
|
9
9
|
class MockConfig
|
10
|
-
attr_accessor :foo, :bar, :nana, :meep, :lalala, :meow, :peebo, :whitelist
|
10
|
+
attr_accessor :foo, :bar, :nana, :meep, :lalala, :meow, :peebo, :whitelist, :blah
|
11
11
|
end
|
12
12
|
|
13
13
|
before do
|
@@ -20,6 +20,7 @@ module PactBroker
|
|
20
20
|
Setting.create(name: 'peebo', type: 'string', value: nil)
|
21
21
|
Setting.create(name: 'unknown', type: 'string', value: nil)
|
22
22
|
Setting.create(name: 'whitelist', type: 'space_delimited_string_list', value: 'foo bar')
|
23
|
+
Setting.create(name: 'blah', type: 'symbol', value: 'boop')
|
23
24
|
end
|
24
25
|
|
25
26
|
let(:configuration) { MockConfig.new }
|
@@ -36,6 +37,11 @@ module PactBroker
|
|
36
37
|
expect(configuration.bar).to eq "bar"
|
37
38
|
end
|
38
39
|
|
40
|
+
it "loads a Symbol setting" do
|
41
|
+
subject
|
42
|
+
expect(configuration.blah).to eq :boop
|
43
|
+
end
|
44
|
+
|
39
45
|
it "loads an Integer setting" do
|
40
46
|
subject
|
41
47
|
expect(configuration.nana).to eq 1
|
@@ -7,7 +7,7 @@ module PactBroker
|
|
7
7
|
describe Save do
|
8
8
|
|
9
9
|
describe "#call" do
|
10
|
-
let(:setting_names) { [:foo, :bar, :wiffle, :meep, :flop, :peebo, :lalala, :meow, :whitelist] }
|
10
|
+
let(:setting_names) { [:foo, :bar, :wiffle, :meep, :flop, :peebo, :lalala, :meow, :whitelist, :blah] }
|
11
11
|
let(:configuration) do
|
12
12
|
double("PactBroker::Configuration",
|
13
13
|
foo: true,
|
@@ -15,6 +15,7 @@ module PactBroker
|
|
15
15
|
wiffle: ["a", "b", "c"],
|
16
16
|
meep: {a: 'thing'},
|
17
17
|
flop: nil,
|
18
|
+
blah: :boop,
|
18
19
|
peebo: 1,
|
19
20
|
lalala: 1.2,
|
20
21
|
meow: Object.new,
|
@@ -23,6 +24,13 @@ module PactBroker
|
|
23
24
|
|
24
25
|
subject { Save.call(configuration, setting_names) }
|
25
26
|
|
27
|
+
it "saves a Symbol" do
|
28
|
+
subject
|
29
|
+
setting = Setting.find(name: 'blah')
|
30
|
+
expect(setting.type).to eq 'symbol'
|
31
|
+
expect(setting.value).to eq 'boop'
|
32
|
+
end
|
33
|
+
|
26
34
|
it "saves a false config setting to the database" do
|
27
35
|
subject
|
28
36
|
setting = Setting.find(name: 'foo')
|
@@ -14,9 +14,38 @@ module PactBroker
|
|
14
14
|
allow(Service).to receive(:logger).and_return(logger)
|
15
15
|
end
|
16
16
|
|
17
|
-
let(:td) { TestDataBuilder.new }
|
18
17
|
let(:logger) { double('logger').as_null_object }
|
19
18
|
|
19
|
+
describe "validate - integration test" do
|
20
|
+
let(:invalid_webhook) { PactBroker::Domain::Webhook.new }
|
21
|
+
|
22
|
+
context "with no uuid" do
|
23
|
+
subject { Service.errors(invalid_webhook) }
|
24
|
+
|
25
|
+
it "does not contain an error for the uuid" do
|
26
|
+
expect(subject.messages).to_not have_key('uuid')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "with a uuid" do
|
31
|
+
subject { Service.errors(invalid_webhook, '') }
|
32
|
+
|
33
|
+
it "merges the uuid errors with the webhook errors" do
|
34
|
+
expect(subject.messages['uuid'].first).to include "can only contain"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe ".valid_uuid_format?" do
|
40
|
+
it 'does something' do
|
41
|
+
expect(Service.valid_uuid_format?("_-bcdefghigHIJKLMNOP")).to be true
|
42
|
+
expect(Service.valid_uuid_format?("HIJKLMNOP")).to be false
|
43
|
+
expect(Service.valid_uuid_format?("abcdefghigHIJKLMNOP\\")).to be false
|
44
|
+
expect(Service.valid_uuid_format?("abcdefghigHIJKLMNOP#")).to be false
|
45
|
+
expect(Service.valid_uuid_format?("abcdefghigHIJKLMNOP$")).to be false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
20
49
|
describe ".delete_by_uuid" do
|
21
50
|
before do
|
22
51
|
td.create_pact_with_hierarchy
|
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.49.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bethany Skurrie
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2020-02-
|
13
|
+
date: 2020-02-13 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: httparty
|