Skip to content

Commit

Permalink
feat: add ${pactbroker.providerVersionNumber} to webhook templates
Browse files Browse the repository at this point in the history
  • Loading branch information
bethesque committed Jun 9, 2018
1 parent ec4e6e9 commit 86bc1ec
Show file tree
Hide file tree
Showing 18 changed files with 134 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Sequel.migration do
change do
alter_table(:triggered_webhooks) do
add_foreign_key(:verification_id, :verifications)
end
end
end
1 change: 1 addition & 0 deletions lib/pact_broker/doc/views/webhooks.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ The following variables may be used in the request parameters or body, and will

`${pactbroker.pactUrl}`: the "permalink" URL to the newly published pact (the URL specifying the consumer version URL, rather than the "/latest" format.)
`${pactbroker.consumerVersionNumber}`: the version number of the most recent consumer version associated with the pact content.
`${pactbroker.providerVersionNumber}`: the provider version number for the verification result

Example usage:

Expand Down
4 changes: 2 additions & 2 deletions lib/pact_broker/domain/webhook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ def request_description
request && request.description
end

def execute pact, options
def execute pact, verification, options
logger.info "Executing #{self}"
request.execute pact, options
request.execute pact, verification, options
end

def to_s
Expand Down
24 changes: 12 additions & 12 deletions lib/pact_broker/domain/webhook_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,21 @@ def display_password
password.nil? ? nil : "**********"
end

def execute pact, options = {}
def execute pact, verification, options = {}
logs = StringIO.new
execution_logger = Logger.new(logs)
begin
execute_and_build_result(pact, options, logs, execution_logger)
execute_and_build_result(pact, verification, options, logs, execution_logger)
rescue StandardError => e
handle_error_and_build_result(e, options, logs, execution_logger)
end
end

private

def execute_and_build_result pact, options, logs, execution_logger
uri = build_uri(pact)
req = build_request(uri, pact, execution_logger)
def execute_and_build_result pact, verification, options, logs, execution_logger
uri = build_uri(pact, verification)
req = build_request(uri, pact, verification, execution_logger)
response = do_request(uri, req)
log_response(response, execution_logger, options)
result = WebhookExecutionResult.new(response, logs.string)
Expand All @@ -80,9 +80,9 @@ def handle_error_and_build_result e, options, logs, execution_logger
WebhookExecutionResult.new(nil, logs.string, e)
end

def build_request uri, pact, execution_logger
def build_request uri, pact, verification, execution_logger
req = http_request(uri)
execution_logger.info "HTTP/1.1 #{method.upcase} #{url_with_credentials(pact)}"
execution_logger.info "HTTP/1.1 #{method.upcase} #{url_with_credentials(pact, verification)}"

headers.each_pair do | name, value |
execution_logger.info Webhooks::RedactLogs.call("#{name}: #{value}")
Expand All @@ -92,7 +92,7 @@ def build_request uri, pact, execution_logger
req.basic_auth(username, password) if username

unless body.nil?
req.body = PactBroker::Webhooks::Render.call(String === body ? body : body.to_json, pact)
req.body = PactBroker::Webhooks::Render.call(String === body ? body : body.to_json, pact, verification)
end

execution_logger.info(req.body) if req.body
Expand Down Expand Up @@ -173,12 +173,12 @@ def http_request(uri)
Net::HTTP.const_get(method.capitalize).new(uri)
end

def build_uri pact
URI(PactBroker::Webhooks::Render.call(url, pact){ | value | CGI::escape(value)} )
def build_uri(pact, verification)
URI(PactBroker::Webhooks::Render.call(url, pact, verification){ | value | CGI::escape(value)} )
end

def url_with_credentials pact
u = build_uri(pact)
def url_with_credentials pact, verification
u = build_uri(pact, verification)
u.userinfo = "#{CGI::escape username}:#{display_password}" if username
u
end
Expand Down
2 changes: 1 addition & 1 deletion lib/pact_broker/pacts/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def update_pact params, existing_pact
updated_pact = pact_repository.update existing_pact.id, params

if existing_pact.json_content != updated_pact.json_content
webhook_service.execute_webhooks updated_pact, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED
webhook_service.execute_webhooks updated_pact, nil, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED
end

updated_pact
Expand Down
3 changes: 2 additions & 1 deletion lib/pact_broker/verifications/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ def create next_verification_number, params, pact
provider_version_number = params.fetch('providerApplicationVersion')
PactBroker::Api::Decorators::VerificationDecorator.new(verification).from_hash(params)
verification.number = next_verification_number
webhook_service.execute_webhooks pact, PactBroker::Webhooks::WebhookEvent::VERIFICATION_PUBLISHED
verification = verification_repository.create(verification, provider_version_number, pact)
webhook_service.execute_webhooks pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_PUBLISHED
verification
end

def errors params
Expand Down
3 changes: 2 additions & 1 deletion lib/pact_broker/webhooks/render.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ def self.call(body, pact, verification = nil, &escaper)
base_url = PactBroker.configuration.base_url
params = {
'${pactbroker.pactUrl}' => PactBroker::Api::PactBrokerUrls.pact_url(base_url, pact),
'${pactbroker.consumerVersionNumber}' => pact.consumer_version_number
'${pactbroker.consumerVersionNumber}' => pact.consumer_version_number,
'${pactbroker.providerVersionNumber}' => verification ? verification.provider_version_number : ""
}

if escaper
Expand Down
3 changes: 2 additions & 1 deletion lib/pact_broker/webhooks/repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,12 @@ def find_by_consumer_and_provider_existing_at consumer, provider, date_time
.collect(&:to_domain)
end

def create_triggered_webhook trigger_uuid, webhook, pact, trigger_type
def create_triggered_webhook trigger_uuid, webhook, pact, verification, trigger_type
db_webhook = Webhook.where(uuid: webhook.uuid).single_record
TriggeredWebhook.create(
status: TriggeredWebhook::STATUS_NOT_RUN,
pact_publication_id: pact.id,
verification: verification,
webhook: db_webhook,
webhook_uuid: db_webhook.uuid,
trigger_uuid: trigger_uuid,
Expand Down
12 changes: 6 additions & 6 deletions lib/pact_broker/webhooks/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ def self.find_all
webhook_repository.find_all
end

def self.execute_webhook_now webhook, pact
triggered_webhook = webhook_repository.create_triggered_webhook(next_uuid, webhook, pact, USER)
def self.execute_webhook_now webhook, pact, verification = nil
triggered_webhook = webhook_repository.create_triggered_webhook(next_uuid, webhook, pact, verification, USER)
options = { failure_log_message: "Webhook execution failed", show_response: PactBroker.configuration.show_webhook_response?}
webhook_execution_result = execute_triggered_webhook_now triggered_webhook, options
if webhook_execution_result.success?
Expand All @@ -85,21 +85,21 @@ def self.find_by_consumer_and_provider consumer, provider
webhook_repository.find_by_consumer_and_provider consumer, provider
end

def self.execute_webhooks pact, event_name
def self.execute_webhooks pact, verification, event_name
webhooks = webhook_repository.find_by_consumer_and_provider_and_event_name pact.consumer, pact.provider, event_name

if webhooks.any?
run_later(webhooks, pact, event_name)
run_later(webhooks, pact, verification, event_name)
else
logger.debug "No webhook found for consumer \"#{pact.consumer.name}\" and provider \"#{pact.provider.name}\""
end
end

def self.run_later webhooks, pact, event_name
def self.run_later webhooks, pact, verification, event_name
trigger_uuid = next_uuid
webhooks.each do | webhook |
begin
triggered_webhook = webhook_repository.create_triggered_webhook(trigger_uuid, webhook, pact, RESOURCE_CREATION)
triggered_webhook = webhook_repository.create_triggered_webhook(trigger_uuid, webhook, pact, verification, RESOURCE_CREATION)
logger.info "Scheduling job for #{webhook.description} with uuid #{webhook.uuid}"
# Bit of a dodgey hack to make sure the request transaction has finished before we execute the webhook
Job.perform_in(5, triggered_webhook: triggered_webhook)
Expand Down
3 changes: 2 additions & 1 deletion lib/pact_broker/webhooks/triggered_webhook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def not_run
associate(:one_to_many, :webhook_executions, :class => "PactBroker::Webhooks::Execution", :key => :triggered_webhook_id, :primary_key => :id, :order => :id)
associate(:many_to_one, :webhook, :class => "PactBroker::Webhooks::Webhook", :key => :webhook_id, :primary_key => :id)
associate(:many_to_one, :pact_publication, :class => "PactBroker::Pacts::PactPublication", :key => :pact_publication_id, :primary_key => :id)
associate(:many_to_one, :verification, :class => "PactBroker::Domain::Verification", :key => :verification_id, :primary_key => :id)
associate(:many_to_one, :provider, :class => "PactBroker::Domain::Pacticipant", :key => :provider_id, :primary_key => :id)
associate(:many_to_one, :consumer, :class => "PactBroker::Domain::Pacticipant", :key => :consumer_id, :primary_key => :id)

Expand All @@ -49,7 +50,7 @@ def execute options
# getting a random 'no method to_domain for null' error
# not sure on which object, so splitting this out into two lines
pact = pact_publication.to_domain
webhook.to_domain.execute(pact, options)
webhook.to_domain.execute(pact, verification, options)
end

def consumer_name
Expand Down
2 changes: 1 addition & 1 deletion spec/integration/webhooks/certificate_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

let(:pact) { td.create_pact_with_hierarchy.and_return(:pact) }

subject { webhook_request.execute(pact) }
subject { webhook_request.execute(pact, nil) }

context "without the correct cacert" do
it "fails" do
Expand Down
51 changes: 27 additions & 24 deletions spec/lib/pact_broker/domain/webhook_request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ module Domain
let(:options) { {failure_log_message: 'oops', show_response: show_response} }
let(:show_response) { true }
let(:pact) { instance_double('PactBroker::Domain::Pact') }
let(:verification) { instance_double('PactBroker::Domain::Verification') }
let(:logs) { execute.logs }

subject do
WebhookRequest.new(
Expand All @@ -33,7 +35,8 @@ module Domain
body: body)
end

let(:logs) { subject.execute(pact, options).logs }
let(:execute) { subject.execute(pact, verification, options) }


describe "description" do
it "returns a brief description of the HTTP request" do
Expand Down Expand Up @@ -65,20 +68,20 @@ module Domain
let(:request_body) { 'body' }

it "renders the url template" do
expect(PactBroker::Webhooks::Render).to receive(:call).with("http://example.org/hook", pact) do | content, pact, verification, &block |
expect(PactBroker::Webhooks::Render).to receive(:call).with("http://example.org/hook", pact, verification) do | content, pact, verification, &block |
expect(content).to eq "http://example.org/hook"
expect(pact).to be pact
expect(verification).to be nil
expect(verification).to be verification
expect(block.call("foo bar")).to eq "foo+bar"
"http://example.org/hook"
end
subject.execute(pact, options)
execute
end

context "when the body is a string" do
it "renders the body template with the String" do
expect(PactBroker::Webhooks::Render).to receive(:call).with('body', pact)
subject.execute(pact, options)
expect(PactBroker::Webhooks::Render).to receive(:call).with('body', pact, verification)
execute
end
end

Expand All @@ -87,20 +90,20 @@ module Domain
let(:request_body) { '{"foo":"bar"}' }

it "renders the body template with JSON" do
expect(PactBroker::Webhooks::Render).to receive(:call).with(request_body, pact)
subject.execute(pact, options)
expect(PactBroker::Webhooks::Render).to receive(:call).with(request_body, pact, verification)
execute
end
end

it "executes the configured request" do
subject.execute(pact, options)
execute
expect(http_request).to have_been_made
end

it "logs the request" do
allow(PactBroker.logger).to receive(:info)
expect(PactBroker.logger).to receive(:info).with(/POST.*example.*text.*body/)
subject.execute(pact, options)
execute
end

it "logs the response" do
Expand All @@ -109,7 +112,7 @@ module Domain
expect(PactBroker.logger).to receive(:info).with(/response.*200/)
expect(PactBroker.logger).to receive(:debug).with(/content-type/)
expect(PactBroker.logger).to receive(:debug).with(/respbod/)
subject.execute(pact, options)
execute
end

describe "execution logs" do
Expand Down Expand Up @@ -204,7 +207,7 @@ module Domain
let(:password) { "password" }

it "uses the credentials" do
subject.execute(pact, options)
execute
expect(http_request_with_basic_auth).to have_been_made
end
end
Expand All @@ -214,7 +217,7 @@ module Domain
let(:password) { "p@$$w0rd!" }

it "uses the credentials" do
subject.execute(pact, options)
execute
expect(http_request_with_basic_auth).to have_been_made
end
end
Expand All @@ -231,7 +234,7 @@ module Domain
end

it "uses SSL" do
subject.execute(pact, options)
execute
expect(https_request).to have_been_made
end
end
Expand All @@ -246,18 +249,18 @@ module Domain
end

it "executes the request without a body" do
subject.execute(pact, options)
execute
expect(http_request).to have_been_made
end
end

context "when the request is successful" do
it "returns a WebhookExecutionResult with success=true" do
expect(subject.execute(pact, options).success?).to be true
expect(execute.success?).to be true
end

it "sets the response on the result" do
expect(subject.execute(pact, options).response).to be_instance_of(Net::HTTPOK)
expect(execute.response).to be_instance_of(Net::HTTPOK)
end
end

Expand All @@ -270,11 +273,11 @@ module Domain
end

it "returns a WebhookExecutionResult with success=false" do
expect(subject.execute(pact, options).success?).to be false
expect(execute.success?).to be false
end

it "sets the response on the result" do
expect(subject.execute(pact, options).response).to be_instance_of(Net::HTTPInternalServerError)
expect(execute.response).to be_instance_of(Net::HTTPInternalServerError)
end
end

Expand All @@ -285,15 +288,15 @@ module Domain
end

it "removes the non UTF-8 characters before saving the logs so they don't blow up the database" do
result = subject.execute(pact, options)
result = execute
expect(result.logs).to include "This has some invalid chars"
end

it "logs that it has cleaned the string to the execution logger" do
logger = double("logger").as_null_object
allow(Logger).to receive(:new).and_return(logger)
expect(logger).to receive(:debug).with(/Note that invalid UTF-8 byte sequences were removed/)
subject.execute(pact, options)
execute
end
end

Expand All @@ -308,15 +311,15 @@ class WebhookTestError < StandardError; end

it "logs the error" do
expect(PactBroker.logger).to receive(:error).with(/Error.*WebhookTestError.*blah/)
subject.execute(pact, options)
execute
end

it "returns a WebhookExecutionResult with success=false" do
expect(subject.execute(pact, options).success?).to be false
expect(execute.success?).to be false
end

it "returns a WebhookExecutionResult with an error" do
expect(subject.execute(pact, options).error).to be_instance_of WebhookTestError
expect(execute.error).to be_instance_of WebhookTestError
end

it "logs the failure_log_message" do
Expand Down
Loading

0 comments on commit 86bc1ec

Please sign in to comment.