Skip to content

Commit

Permalink
feat(webhook templating): add support for ${pactbroker.pactUrl} in qu…
Browse files Browse the repository at this point in the history
…ery and body

For #54
  • Loading branch information
bethesque committed Nov 9, 2017
1 parent 8424e14 commit 0eed596
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 21 deletions.
2 changes: 2 additions & 0 deletions lib/pact_broker/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'pact_broker/project_root'
require 'rack-protection'
require 'rack/hal_browser'
require 'rack/pact_broker/store_base_url'
require 'rack/pact_broker/add_pact_broker_version_header'
require 'rack/pact_broker/convert_file_extension_to_accept_header'
require 'rack/pact_broker/database_transaction'
Expand Down Expand Up @@ -106,6 +107,7 @@ def configure_middleware
# NOTE THAT NONE OF THIS IS PROTECTED BY AUTH - is that ok?
@app_builder.use Rack::Protection, except: [:path_traversal, :remote_token, :session_hijacking, :http_origin]
@app_builder.use Rack::PactBroker::InvalidUriProtection
@app_builder.use Rack::PactBroker::StoreBaseURL
@app_builder.use Rack::PactBroker::AddPactBrokerVersionHeader
@app_builder.use Rack::Static, :urls => ["/stylesheets", "/css", "/fonts", "/js", "/javascripts", "/images"], :root => PactBroker.project_root.join("public")
@app_builder.use Rack::Static, :urls => ["/favicon.ico"], :root => PactBroker.project_root.join("public/images"), header_rules: [[:all, {'Content-Type' => 'image/x-icon'}]]
Expand Down
4 changes: 4 additions & 0 deletions lib/pact_broker/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ def enable_badge_resources= enable_badge_resources
self.enable_public_badge_access = enable_badge_resources
end

def base_url
ENV['PACT_BROKER_BASE_URL']
end

def save_to_database
# Can't require a Sequel::Model class before the connection has been set
require 'pact_broker/config/save'
Expand Down
46 changes: 30 additions & 16 deletions lib/pact_broker/domain/webhook_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require 'pact_broker/messages'
require 'net/http'
require 'pact_broker/webhooks/redact_logs'
require 'pact_broker/api/pact_broker_urls'

module PactBroker

Expand Down Expand Up @@ -51,17 +52,18 @@ def execute pact, options = {}
logs = StringIO.new
execution_logger = Logger.new(logs)
begin
execute_and_build_result(options, logs, execution_logger)
execute_and_build_result(pact, 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 options, logs, execution_logger
req = build_request(execution_logger)
response = do_request(req)
def execute_and_build_result pact, options, logs, execution_logger
uri = build_uri(pact)
req = build_request(uri, pact, execution_logger)
response = do_request(uri, req)
log_response(response, execution_logger)
result = WebhookExecutionResult.new(response, logs.string)
log_completion_message(options, execution_logger, result.success?)
Expand All @@ -75,9 +77,9 @@ def handle_error_and_build_result e, options, logs, execution_logger
WebhookExecutionResult.new(nil, logs.string, e)
end

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

headers.each_pair do | name, value |
execution_logger.info Webhooks::RedactLogs.call("#{name}: #{value}")
Expand All @@ -88,17 +90,17 @@ def build_request execution_logger

unless body.nil?
if String === body
req.body = body
req.body = gsub_body(pact, body)
else
req.body = body.to_json
req.body = gsub_body(pact, body.to_json)
end
end

execution_logger.info req.body
req
end

def do_request req
def do_request uri, req
logger.info "Making webhook #{uuid} request #{to_s}"
Net::HTTP.start(uri.hostname, uri.port,
:use_ssl => uri.scheme == 'https') do |http|
Expand Down Expand Up @@ -126,19 +128,31 @@ def to_s
"#{method.upcase} #{url}, username=#{username}, password=#{display_password}, headers=#{headers}, body=#{body}"
end

def http_request
Net::HTTP.const_get(method.capitalize).new(url)
def http_request(uri)
Net::HTTP.const_get(method.capitalize).new(uri)
end

def uri
URI(url)
def build_uri pact
URI(gsub_url(pact, url))
end

def url_with_credentials
u = URI(url)
def url_with_credentials pact
u = build_uri(pact)
u.userinfo = "#{username}:#{display_password}" if username
u
end

def gsub_body pact, body
base_url = PactBroker.configuration.base_url
body.gsub('${pactbroker.pactUrl}', PactBroker::Api::PactBrokerUrls.pact_url(base_url, pact))
end

def gsub_url pact, url
base_url = PactBroker.configuration.base_url
pact_url = PactBroker::Api::PactBrokerUrls.pact_url(base_url, pact)
escaped_pact_url = CGI::escape(pact_url)
url.gsub('${pactbroker.pactUrl}', escaped_pact_url)
end
end
end
end
14 changes: 14 additions & 0 deletions lib/rack/pact_broker/store_base_url.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module Rack
module PactBroker
class StoreBaseURL
def initialize app
@app = app
end

def call(env)
ENV['PACT_BROKER_BASE_URL'] ||= ::Rack::Request.new(env).base_url
@app.call(env)
end
end
end
end
2 changes: 1 addition & 1 deletion script/seed.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def publish_pact params = {}
.create_label("microservice")
.create_provider("Bar")
.create_label("microservice")
.create_webhook(method: 'GET', url: 'http://localhost:9393/')
.create_webhook(method: 'GET', url: 'http://localhost:9393?url=${pactbroker.pactUrl}', body: '${pactbroker.pactUrl}')
.create_consumer_version("1.2.100")
.publish_pact
.create_verification(provider_version: "1.4.234", success: true, execution_date: DateTime.now - 15)
Expand Down
6 changes: 5 additions & 1 deletion script/webhook-server.ru
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
require 'rack/utils'

count = 0
run -> (env) {
count += 1
status = (count % 3 == 0) ? 200 : 500
puts "Received request"; [status, {}, ["Hello. This might be an error.\n"]]
puts Rack::Utils.parse_nested_query(env['QUERY_STRING'])
puts env['rack.input'].read
[status, {}, ["Hello. This might be an error.\n"]]
}
11 changes: 8 additions & 3 deletions spec/features/execute_webhook_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@
let(:td) { TestDataBuilder.new }

before do
td.create_pact_with_hierarchy("Some Consumer", "1", "Some Provider")
.create_webhook(method: 'POST')
ENV['PACT_BROKER_BASE_URL'] = 'http://example.org'
td.create_pact_with_hierarchy("Foo", "1", "Bar")
.create_webhook(method: 'POST', body: '${pactbroker.pactUrl}')
end

after do
ENV.delete('PACT_BROKER_BASE_URL')
end

let(:path) { "/webhooks/#{td.webhook.uuid}/execute" }
Expand All @@ -18,7 +23,7 @@

context "when the execution is successful" do
let!(:request) do
stub_request(:post, /http/).to_return(:status => 200)
stub_request(:post, /http/).with(body: 'http://example.org/pacts/provider/Bar/consumer/Foo/version/1').to_return(:status => 200)
end

it "performs the HTTP request" do
Expand Down
49 changes: 49 additions & 0 deletions spec/lib/pact_broker/domain/webhook_request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ module PactBroker
module Domain

describe WebhookRequest do
before do
allow(PactBroker::Api::PactBrokerUrls).to receive(:pact_url).and_return('http://example.org/pact-url')
allow(PactBroker.configuration).to receive(:base_url).and_return('http://example.org')
end

let(:username) { nil }
let(:password) { nil }
Expand All @@ -29,6 +33,7 @@ module Domain

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


describe "description" do
it "returns a brief description of the HTTP request" do
expect(subject.description).to eq 'POST example.org'
Expand Down Expand Up @@ -57,6 +62,50 @@ module Domain
to_return(:status => 200, :body => "respbod", :headers => {'Content-Type' => 'text/foo, blah'})
end

describe "when the String body contains a ${pactbroker.pactUrl} parameter" do
let!(:http_request) do
stub_request(:post, "http://example.org/hook").
with(:headers => {'Content-Type'=>'text/plain'}, :body => "<xml><url>http://example.org/pact-url</url></xml>").
to_return(:status => 200)
end

let(:body) { "<xml><url>${pactbroker.pactUrl}</url></xml>" }

it "replaces the token with the live value" do
subject.execute(pact, options)
expect(http_request).to have_been_made
end
end

describe "when the JSON body contains a ${pactbroker.pactUrl} parameter" do
let!(:http_request) do
stub_request(:post, "http://example.org/hook").
with(:headers => {'Content-Type'=>'text/plain'}, :body => '{"url":"http://example.org/pact-url"}').
to_return(:status => 200)
end

let(:body) { { url: '${pactbroker.pactUrl}' } }

it "replaces the token with the live value" do
subject.execute(pact, options)
expect(http_request).to have_been_made
end
end

describe "when the URL contains a ${pactbroker.pactUrl} parameter" do
let!(:http_request) do
stub_request(:post, "http://example.org/hook?url=http%3A%2F%2Fexample.org%2Fpact-url").
to_return(:status => 200)
end

let(:url) { 'http://example.org/hook?url=${pactbroker.pactUrl}' }

it "replaces the token with the live value" do
subject.execute(pact, options)
expect(http_request).to have_been_made
end
end

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

0 comments on commit 0eed596

Please sign in to comment.