Skip to content

Commit 00f60c1

Browse files
committed
feat: add resource to view the triggered webhooks for a pact publication
1 parent 7379e23 commit 00f60c1

16 files changed

+301
-26
lines changed

lib/pact_broker/api.rb

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ module PactBroker
6060
add ['webhooks', 'consumer', :consumer_name], Api::Resources::Webhooks, {resource_name: "consumer_webhooks"}
6161
add ['pacts', 'provider', :provider_name, 'consumer', :consumer_name, 'webhooks'], Api::Resources::PactWebhooks, {resource_name: "pact_webhooks"}
6262
add ['pacts', 'provider', :provider_name, 'consumer', :consumer_name, 'webhooks', 'status'], Api::Resources::PactWebhooksStatus, {resource_name: "pact_webhooks_status"}
63+
add ['pacts', 'provider', :provider_name, 'consumer', :consumer_name, 'version', :consumer_version_number, 'triggered-webhooks'], Api::Resources::PactTriggeredWebhooks, {resource_name: "pact_triggered_webhooks"}
6364

6465
add ['webhooks', :uuid ], Api::Resources::Webhook, {resource_name: "webhook"}
6566
add ['webhooks', :uuid, 'trigger', :trigger_uuid, 'logs' ], Api::Resources::TriggeredWebhookLogs, {resource_name: "triggered_webhook_logs"}

lib/pact_broker/api/decorators/pact_decorator.rb

+7
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,13 @@ def to_hash(options = {})
141141
}
142142
end
143143

144+
link :'pb:triggered-webhooks' do | options |
145+
{
146+
title: "Webhooks triggered by the publication of this pact",
147+
href: pact_triggered_webhooks_url(represented, options.fetch(:base_url))
148+
}
149+
end
150+
144151
curies do | options |
145152
[{
146153
name: :pb,

lib/pact_broker/api/decorators/pact_webhooks_status_decorator.rb

+1-26
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,12 @@
11
require_relative 'base_decorator'
22
require_relative 'timestamps'
33
require_relative 'pact_version_decorator'
4+
require_relative 'triggered_webhook_decorator'
45

56
module PactBroker
67
module Api
78
module Decorators
89

9-
class TriggeredWebhookDecorator < BaseDecorator
10-
property :request_description, as: :name
11-
property :status
12-
property :number_of_attempts_made, as: :attemptsMade
13-
property :number_of_attempts_remaining, as: :attemptsRemaining
14-
property :trigger_type, as: :triggerType
15-
16-
property :created_at, as: :triggeredAt
17-
18-
link :logs do | context |
19-
{
20-
href: triggered_webhook_logs_url(represented, context[:base_url]),
21-
title: "Webhook execution logs",
22-
name: represented.request_description
23-
}
24-
end
25-
26-
link :'pb:webhook' do | context |
27-
{
28-
href: webhook_url(represented.webhook_uuid, context[:base_url]),
29-
title: "Webhook",
30-
name: represented.request_description
31-
}
32-
end
33-
end
34-
3510
class PactWebhooksStatusDecorator < BaseDecorator
3611

3712
property :summary, exec_context: :decorator do
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
require_relative 'base_decorator'
2+
3+
module PactBroker
4+
module Api
5+
module Decorators
6+
class TriggeredWebhookDecorator < BaseDecorator
7+
property :request_description, as: :name
8+
property :status
9+
property :number_of_attempts_made, as: :attemptsMade
10+
property :number_of_attempts_remaining, as: :attemptsRemaining
11+
property :trigger_type, as: :triggerType
12+
13+
property :created_at, as: :triggeredAt
14+
15+
link :logs do | context |
16+
{
17+
href: triggered_webhook_logs_url(represented, context[:base_url]),
18+
title: "Webhook execution logs",
19+
name: represented.request_description
20+
}
21+
end
22+
23+
link :'pb:webhook' do | context |
24+
{
25+
href: webhook_url(represented.webhook_uuid, context[:base_url]),
26+
title: "Webhook",
27+
name: represented.request_description
28+
}
29+
end
30+
end
31+
end
32+
end
33+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
require 'pact_broker/api/decorators/base_decorator'
2+
require 'pact_broker/api/decorators/triggered_webhook_decorator'
3+
4+
module PactBroker
5+
module Api
6+
module Decorators
7+
class TriggeredWebhooksDecorator < BaseDecorator
8+
collection :entries, as: :triggeredWebhooks, embedded: true, :extend => PactBroker::Api::Decorators::TriggeredWebhookDecorator
9+
10+
link :self do | options |
11+
{
12+
title: options.fetch(:resource_title),
13+
href: options.fetch(:resource_url)
14+
}
15+
end
16+
end
17+
end
18+
end
19+
end

lib/pact_broker/api/pact_broker_urls.rb

+4
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ def webhooks_status_url consumer, provider, base_url = ''
172172
"#{webhooks_for_pact_url(consumer, provider, base_url)}/status"
173173
end
174174

175+
def pact_triggered_webhooks_url pact, base_url = ''
176+
"#{pact_url(base_url, pact)}/triggered-webhooks"
177+
end
178+
175179
def triggered_webhook_logs_url triggered_webhook, base_url
176180
"#{base_url}/webhooks/#{triggered_webhook.webhook_uuid}/trigger/#{triggered_webhook.trigger_uuid}/logs"
177181
end

lib/pact_broker/api/resources/base_resource.rb

+4
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ def consumer
166166
def provider
167167
@provider ||= identifier_from_path[:provider_name] && find_pacticipant(identifier_from_path[:provider_name], "provider")
168168
end
169+
170+
def pact
171+
@pact ||= pact_service.find_pact(pact_params)
172+
end
169173
end
170174
end
171175
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
require 'pact_broker/api/decorators/triggered_webhooks_decorator'
2+
3+
module PactBroker
4+
module Api
5+
module Resources
6+
class PactTriggeredWebhooks < BaseResource
7+
def allowed_methods
8+
["GET"]
9+
end
10+
11+
def content_types_provided
12+
[["application/hal+json", :to_json]]
13+
end
14+
15+
def resource_exists?
16+
!!pact
17+
end
18+
19+
def to_json
20+
Decorators::TriggeredWebhooksDecorator.new(triggered_webhooks).to_json(decorator_options)
21+
end
22+
23+
private
24+
25+
def triggered_webhooks
26+
webhook_service.find_triggered_webhooks_for_pact(pact)
27+
end
28+
29+
def resource_title
30+
"Webhooks triggered by the publication of the #{pact.name[0].downcase}#{pact.name[1..-1]}"
31+
end
32+
33+
def decorator_options
34+
{
35+
user_options: decorator_context.merge(resource_title: resource_title)
36+
}
37+
end
38+
end
39+
end
40+
end
41+
end

lib/pact_broker/domain/pact.rb

+4
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ def version_and_updated_date
4949
def content_hash
5050
JSON.parse(json_content, PACT_PARSING_OPTIONS)
5151
end
52+
53+
def pact_publication_id
54+
id
55+
end
5256
end
5357

5458
end

lib/pact_broker/webhooks/repository.rb

+8
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,14 @@ def find_latest_triggered_webhooks consumer, provider
177177
.all
178178
end
179179

180+
def find_triggered_webhooks_for_pact pact
181+
PactBroker::Webhooks::TriggeredWebhook
182+
.where(pact_publication_id: pact.pact_publication_id)
183+
.eager(:webhook)
184+
.eager(:webhook_executions)
185+
.reverse(:created_at, :id)
186+
end
187+
180188
def fail_retrying_triggered_webhooks
181189
TriggeredWebhook.retrying.update(status: TriggeredWebhook::STATUS_FAILURE)
182190
end

lib/pact_broker/webhooks/service.rb

+4
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ def self.find_latest_triggered_webhooks consumer, provider
128128
def self.fail_retrying_triggered_webhooks
129129
webhook_repository.fail_retrying_triggered_webhooks
130130
end
131+
132+
def self.find_triggered_webhooks_for_pact pact
133+
webhook_repository.find_triggered_webhooks_for_pact(pact)
134+
end
131135
end
132136
end
133137
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
RSpec.describe "Get triggered webhooks for pact" do
2+
before do
3+
td.create_pact_with_hierarchy
4+
.create_webhook
5+
.create_triggered_webhook
6+
.create_webhook_execution
7+
end
8+
9+
let(:td) { TestDataBuilder.new }
10+
let(:path) { PactBroker::Api::PactBrokerUrls.pact_triggered_webhooks_url(td.pact) }
11+
let(:json_response_body) { JSON.parse(subject.body) }
12+
13+
subject { get(path); last_response }
14+
15+
it { is_expected.to be_a_hal_json_success_response }
16+
17+
it "contains a list of triggered webhooks" do
18+
expect(json_response_body['_embedded']['triggeredWebhooks'].size).to be 1
19+
end
20+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
require 'pact_broker/api/decorators/triggered_webhook_decorator'
2+
3+
module PactBroker
4+
module Api
5+
module Decorators
6+
describe TriggeredWebhookDecorator do
7+
let(:triggered_webhook) do
8+
double('PactBroker::Webhooks::TriggeredWebhook',
9+
trigger_type: PactBroker::Webhooks::TriggeredWebhook::TRIGGER_TYPE_RESOURCE_CREATION,
10+
status: status,
11+
failure?: failure,
12+
retrying?: retrying,
13+
trigger_uuid: '1234',
14+
webhook_uuid: '4321',
15+
request_description: "GET http://foo",
16+
pact_publication: pact,
17+
number_of_attempts_made: 1,
18+
number_of_attempts_remaining: 2,
19+
created_at: DateTime.new(2017),
20+
updated_at: DateTime.new(2017)
21+
)
22+
end
23+
24+
let(:pact) do
25+
double('pact',
26+
provider: double(name: 'provider'),
27+
consumer: double(name: 'consumer'),
28+
consumer_version_number: '1',
29+
name: 'foo '
30+
)
31+
end
32+
33+
let(:failure) { false }
34+
let(:retrying) { false }
35+
let(:status) { PactBroker::Webhooks::TriggeredWebhook::STATUS_SUCCESS }
36+
let(:logs_url) { "http://example.org/webhooks/4321/trigger/1234/logs" }
37+
let(:user_options) { { base_url: "http://example.org" } }
38+
39+
let(:json) do
40+
TriggeredWebhookDecorator.new(triggered_webhook).to_json(user_options: user_options)
41+
end
42+
43+
subject { JSON.parse(json, symbolize_names: true) }
44+
45+
it "includes a link to the logs" do
46+
expect(subject[:_links][:logs][:href]).to eq logs_url
47+
end
48+
49+
it "includes a link to the webhook" do
50+
expect(subject[:_links][:'pb:webhook'][:href]).to eq "http://example.org/webhooks/4321"
51+
end
52+
53+
it "includes the triggered webhooks properties" do
54+
expect(subject).to include(
55+
status: 'success',
56+
triggerType: 'resource_creation',
57+
attemptsMade: 1,
58+
attemptsRemaining: 2
59+
)
60+
end
61+
end
62+
end
63+
end
64+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
require 'pact_broker/api/decorators/triggered_webhooks_decorator'
2+
require 'pact_broker/webhooks/triggered_webhook'
3+
4+
module PactBroker
5+
module Api
6+
module Decorators
7+
describe TriggeredWebhooksDecorator do
8+
let(:triggered_webhook) do
9+
instance_double(PactBroker::Webhooks::TriggeredWebhook).as_null_object
10+
end
11+
let(:decorator) { TriggeredWebhooksDecorator.new([triggered_webhook]) }
12+
let(:user_options) { { resource_title: "Title", resource_url: "http://url" } }
13+
let(:json) { decorator.to_json(user_options: user_options) }
14+
15+
subject { JSON.parse(json) }
16+
17+
it "includes a self relation" do
18+
expect(subject['_links']['self']['title']).to eq "Title"
19+
expect(subject['_links']['self']['href']).to eq "http://url"
20+
end
21+
22+
it "includes an embedded list of triggered webhooks" do
23+
expect(subject['_embedded']['triggeredWebhooks']).to be_instance_of(Array)
24+
end
25+
end
26+
end
27+
end
28+
end

spec/lib/pact_broker/api/pact_broker_urls_spec.rb

+9
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,21 @@ module Api
55
describe PactBrokerUrls do
66

77
let(:base_url) { "http://example.org" }
8+
let(:pact) { double('pact', consumer: consumer, provider: provider, consumer_version_number: "123") }
9+
let(:consumer) { double('pacticipant', name: "Foo") }
10+
let(:provider) { double('pacticipant', name: "Bar") }
811

912
describe "templated_tag_url_for_pacticipant" do
1013
subject { PactBrokerUrls.templated_tag_url_for_pacticipant("Bar", base_url) }
1114

1215
it { is_expected.to eq "http://example.org/pacticipants/Bar/versions/{version}/tags/{tag}" }
1316
end
17+
18+
describe "pact_triggered_webhooks_url" do
19+
subject { PactBrokerUrls.pact_triggered_webhooks_url(pact, base_url) }
20+
21+
it { is_expected.to eq "http://example.org/pacts/provider/Bar/consumer/Foo/version/123/triggered-webhooks" }
22+
end
1423
end
1524
end
1625
end

0 commit comments

Comments
 (0)