Skip to content

Commit

Permalink
feat(verification webhooks): add events to webhooks to allow differen…
Browse files Browse the repository at this point in the history
…tiation between pact and verification webhooks
  • Loading branch information
bethesque committed Nov 18, 2017
1 parent 528034c commit 356c023
Show file tree
Hide file tree
Showing 15 changed files with 175 additions and 41 deletions.
14 changes: 14 additions & 0 deletions db/migrations/20171117_create_webhook_events.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require_relative 'migration_helper'

Sequel.migration do
change do
create_table(:webhook_events, charset: 'utf8') do
primary_key :id
foreign_key :webhook_id, :webhooks, on_delete: :cascade
String :name
DateTime :created_at, null: false
DateTime :updated_at, null: false
index [:id, :name], unique: true, name: 'uq_webhook_id_name'
end
end
end
18 changes: 18 additions & 0 deletions db/migrations/20171118_create_webhook_events.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
require_relative 'migration_helper'

Sequel.migration do
up do
from(:webhooks).each do | webhook |
from(:webhook_events).insert(
webhook_id: webhook[:id],
name: 'contract_changed',
created_at: DateTime.now,
updated_at: DateTime.now
)
end
end

down do

end
end
11 changes: 10 additions & 1 deletion lib/pact_broker/api/contracts/webhook_contract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ module PactBroker
module Api
module Contracts
class WebhookContract < Reform::Form
property :request

validation do
configure do
config.messages_file = File.expand_path("../../../locale/en.yml", __FILE__)
end

required(:request).filled
required(:events).maybe(min_size?: 1)
end

property :request do
Expand All @@ -39,6 +39,15 @@ def valid_url?(value)
required(:url).filled(:valid_url?)
end
end

collection :events do
property :name

validation do
required(:name).filled
end
end

end
end
end
Expand Down
32 changes: 27 additions & 5 deletions lib/pact_broker/api/decorators/webhook_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@
require 'pact_broker/api/decorators/webhook_request_decorator'
require 'pact_broker/api/decorators/timestamps'
require 'pact_broker/domain/webhook_request'
require 'pact_broker/webhooks/webhook_event'
require 'pact_broker/api/decorators/basic_pacticipant_decorator'
require_relative 'pact_pacticipant_decorator'
require_relative 'pacticipant_decorator'

module PactBroker
module Api
module Decorators
class WebhookDecorator < BaseDecorator

property :request, :class => PactBroker::Domain::WebhookRequest, :extend => WebhookRequestDecorator
class WebhookEventDecorator < BaseDecorator
property :name
end

include Timestamps
property :request, :class => PactBroker::Domain::WebhookRequest, extend: WebhookRequestDecorator
collection :events, :class => PactBroker::Webhooks::WebhookEvent, extend: WebhookEventDecorator

property :consumer, :extend => PactBroker::Api::Decorators::BasicPacticipantDecorator, :embedded => true, writeable: false
property :provider, :extend => PactBroker::Api::Decorators::BasicPacticipantDecorator, :embedded => true, writeable: false
include Timestamps

link :self do | options |
{
Expand All @@ -31,9 +36,26 @@ class WebhookDecorator < BaseDecorator
}
end


link :'pb:consumer' do | options |
{
title: "Consumer",
name: represented.consumer.name,
href: pacticipant_url(options.fetch(:base_url), represented.consumer)
}
end

link :'pb:provider' do | options |
{
title: "Provider",
name: represented.provider.name,
href: pacticipant_url(options.fetch(:base_url), represented.provider)
}
end

link :'pb:pact-webhooks' do | options |
{
title: "All webhooks for the pact between #{represented.consumer.name} and #{represented.provider.name}",
title: "All webhooks for consumer #{represented.consumer.name} and provider #{represented.provider.name}",
href: webhooks_for_pact_url(represented.consumer, represented.provider, options[:base_url])
}
end
Expand Down
3 changes: 2 additions & 1 deletion lib/pact_broker/domain/webhook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Webhook
include Messages
include Logging

attr_accessor :uuid, :consumer, :provider, :request, :created_at, :updated_at
attr_accessor :uuid, :consumer, :provider, :request, :created_at, :updated_at, :events
attr_reader :attributes

def initialize attributes = {}
Expand All @@ -19,6 +19,7 @@ def initialize attributes = {}
@request = attributes[:request]
@consumer = attributes[:consumer]
@provider = attributes[:provider]
@events = attributes[:events]
@created_at = attributes[:created_at]
@updated_at = attributes[:updated_at]
end
Expand Down
8 changes: 8 additions & 0 deletions lib/pact_broker/webhooks/repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'pact_broker/domain/pacticipant'
require 'pact_broker/db'
require 'pact_broker/webhooks/webhook'
require 'pact_broker/webhooks/webhook_event'
require 'pact_broker/webhooks/triggered_webhook'
require 'pact_broker/webhooks/latest_triggered_webhook'
require 'pact_broker/webhooks/execution'
Expand All @@ -21,6 +22,9 @@ def create uuid, webhook, consumer, provider
webhook.request.headers.each_pair do | name, value |
db_webhook.add_header PactBroker::Webhooks::WebhookHeader.from_domain(name, value, db_webhook.id)
end
(webhook.events || []).each do | webhook_event |
db_webhook.add_event(webhook_event)
end
find_by_uuid db_webhook.uuid
end

Expand All @@ -32,9 +36,13 @@ def update_by_uuid uuid, webhook
existing_webhook = Webhook.find(uuid: uuid)
existing_webhook.update_from_domain(webhook).save
existing_webhook.headers.collect(&:delete)
existing_webhook.events.collect(&:delete)
webhook.request.headers.each_pair do | name, value |
existing_webhook.add_header PactBroker::Webhooks::WebhookHeader.from_domain(name, value, existing_webhook.id)
end
(webhook.events || []).each do | webhook_event |
existing_webhook.add_event(webhook_event)
end
find_by_uuid uuid
end

Expand Down
3 changes: 3 additions & 0 deletions lib/pact_broker/webhooks/webhook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class Webhook < Sequel::Model
set_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)

one_to_many :events, :class => "PactBroker::Webhooks::WebhookEvent", :reciprocal => :webhook
one_to_many :headers, :class => "PactBroker::Webhooks::WebhookHeader", :reciprocal => :webhook

dataset_module do
Expand Down Expand Up @@ -41,6 +43,7 @@ def to_domain
uuid: uuid,
consumer: consumer,
provider: provider,
events: events,
request: Domain::WebhookRequest.new(request_attributes),
created_at: created_at,
updated_at: updated_at)
Expand Down
16 changes: 16 additions & 0 deletions lib/pact_broker/webhooks/webhook_event.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
require 'sequel'
require 'pact_broker/repositories/helpers'

module PactBroker
module Webhooks
class WebhookEvent < Sequel::Model

dataset_module do
include PactBroker::Repositories::Helpers
end

end

WebhookEvent.plugin :timestamps, update_on_create: true
end
end
5 changes: 4 additions & 1 deletion spec/features/create_webhook_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
describe "Creating a webhook" do

before do
TestDataBuilder.new.create_pact_with_hierarchy("Some Consumer", "1", "Some Provider").and_return(:pact)
TestDataBuilder.new.create_pact_with_hierarchy("Some Consumer", "1", "Some Provider")
end

let(:path) { "/webhooks/provider/Some%20Provider/consumer/Some%20Consumer" }
Expand Down Expand Up @@ -38,6 +38,9 @@

let(:webhook_hash) do
{
events: [{
name: 'something_happened'
}],
request: {
method: 'POST',
url: 'http://example.org',
Expand Down
3 changes: 3 additions & 0 deletions spec/fixtures/webhook_valid.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"events": [{
"name": "something_happened"
}],
"request": {
"method": "POST",
"url": "http://some.url",
Expand Down
20 changes: 20 additions & 0 deletions spec/lib/pact_broker/api/contracts/webhook_contract_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,26 @@ def valid_webhook_with
end
end

context "with no events defined" do
let(:json) { {}.to_json }

it "contains an error for missing request, I wish I could work out how not to have the second error" do
expect(subject.errors[:events]).to eq ["is missing", "size cannot be less than 1"]
end
end

context "with empty events" do
let(:json) do
valid_webhook_with do |hash|
hash['events'] = []
end
end

it "contains an error for missing request" do
expect(subject.errors[:events]).to eq ["size cannot be less than 1"]
end
end

context "with no method" do
let(:json) do
valid_webhook_with do |hash|
Expand Down
37 changes: 18 additions & 19 deletions spec/lib/pact_broker/api/decorators/webhook_decorator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module Decorators

let(:consumer) { Domain::Pacticipant.new(name: 'Consumer') }
let(:provider) { Domain::Pacticipant.new(name: 'Provider') }
let(:event) { Webhooks::WebhookEvent.new(name: 'something_happened') }
let(:created_at) { DateTime.now }
let(:updated_at) { created_at + 1 }

Expand All @@ -30,6 +31,7 @@ module Decorators
uuid: 'some-uuid',
consumer: consumer,
provider: provider,
events: [event],
created_at: created_at,
updated_at: updated_at
)
Expand All @@ -44,26 +46,14 @@ module Decorators
expect(parsed_json[:request]).to eq request
end

it 'includes an embedded consumer' do
expect(parsed_json[:_embedded][:consumer]).to eq ({
name: 'Consumer',
_links: {
self: {
href: 'http://example.org/pacticipants/Consumer'
}
}
})
it 'includes a link to the consumer' do
expect(parsed_json[:_links][:'pb:consumer'][:name]).to eq 'Consumer'
expect(parsed_json[:_links][:'pb:consumer'][:href]).to eq 'http://example.org/pacticipants/Consumer'
end

it 'includes an embedded provider' do
expect(parsed_json[:_embedded][:provider]).to eq ({
name: 'Provider',
_links: {
self: {
href: 'http://example.org/pacticipants/Provider'
}
}
})
it 'includes a link to the provider' do
expect(parsed_json[:_links][:'pb:provider'][:name]).to eq 'Provider'
expect(parsed_json[:_links][:'pb:provider'][:href]).to eq 'http://example.org/pacticipants/Provider'
end

it 'includes a link to itself' do
Expand All @@ -83,6 +73,10 @@ module Decorators
expect(parsed_json[:_links][:'pb:execute'][:href]).to eq 'http://example.org/webhooks/some-uuid/execute'
end

it 'includes the events' do
expect(parsed_json[:events].first).to eq name: 'something_happened'
end

it 'includes timestamps' do
expect(parsed_json[:createdAt]).to eq created_at.xmlschema
expect(parsed_json[:updatedAt]).to eq updated_at.xmlschema
Expand All @@ -97,7 +91,8 @@ module Decorators
end

describe 'from_json' do
let(:hash) { { request: request } }
let(:hash) { { request: request, events: [event] } }
let(:event) { {name: 'something_happened'} }
let(:json) { hash.to_json }
let(:webhook) { Domain::Webhook.new }
let(:parsed_object) { subject.from_json(json) }
Expand All @@ -117,6 +112,10 @@ module Decorators
it 'parses the request body' do
expect(parsed_object.request.body).to eq 'some' => 'body'
end

it 'parses the events' do
expect(parsed_object.events.first.name).to eq 'something_happened'
end
end
end
end
Expand Down
Loading

0 comments on commit 356c023

Please sign in to comment.