pact_broker 2.4.2 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.travis.yml +4 -2
- data/CHANGELOG.md +54 -0
- data/DEVELOPER_DOCUMENTATION.md +11 -7
- data/README.md +5 -1
- data/UPGRADING.md +18 -0
- data/db/migrations/19_make_pact_version_content_sha_not_nullable.rb +9 -1
- data/db/migrations/25_make_pv_pacticipants_mandatory.rb +8 -0
- data/db/migrations/38_create_triggered_webhooks_table.rb +19 -0
- data/db/migrations/39_add_triggered_webhooks_fk_to_execution.rb +24 -0
- data/db/migrations/40_create_latest_triggered_webhooks_view.rb +24 -0
- data/db/migrations/41_migrate_execution_data.rb +47 -0
- data/db/test/backwards_compatibility/.rspec +3 -0
- data/db/test/backwards_compatibility/Appraisals +49 -0
- data/db/test/backwards_compatibility/Gemfile +11 -0
- data/db/test/backwards_compatibility/Rakefile +55 -0
- data/db/test/backwards_compatibility/config.ru +18 -0
- data/db/test/backwards_compatibility/gemfiles/1.18.0.gemfile +14 -0
- data/db/test/backwards_compatibility/gemfiles/1.18.0.gemfile.lock +210 -0
- data/db/test/backwards_compatibility/gemfiles/2.0.0.gemfile +14 -0
- data/db/test/backwards_compatibility/gemfiles/2.0.0.gemfile.lock +208 -0
- data/db/test/backwards_compatibility/gemfiles/2.1.0.gemfile +14 -0
- data/db/test/backwards_compatibility/gemfiles/2.1.0.gemfile.lock +209 -0
- data/db/test/backwards_compatibility/gemfiles/2.2.0.gemfile +14 -0
- data/db/test/backwards_compatibility/gemfiles/2.2.0.gemfile.lock +197 -0
- data/db/test/backwards_compatibility/gemfiles/2.3.0.gemfile +13 -0
- data/db/test/backwards_compatibility/gemfiles/2.3.0.gemfile.lock +196 -0
- data/db/test/backwards_compatibility/gemfiles/2.4.2.gemfile +13 -0
- data/db/test/backwards_compatibility/gemfiles/2.4.2.gemfile.lock +196 -0
- data/db/test/backwards_compatibility/gemfiles/head.gemfile +13 -0
- data/db/test/backwards_compatibility/gemfiles/head.gemfile.lock +200 -0
- data/db/test/backwards_compatibility/spec/fixtures/foo-bar.json +22 -0
- data/db/test/backwards_compatibility/spec/publish_pact_spec.rb +72 -0
- data/db/test/backwards_compatibility/spec/spec_helper.rb +20 -0
- data/db/test/backwards_compatibility/spec/support/fixture_helpers.rb +12 -0
- data/db/test/backwards_compatibility/spec/support/request_helpers.rb +20 -0
- data/example/Gemfile +2 -2
- data/example/pact_broker_database.sqlite3 +0 -0
- data/lib/pact_broker/api/decorators/pact_collection_decorator.rb +1 -2
- data/lib/pact_broker/api/decorators/pact_decorator.rb +12 -10
- data/lib/pact_broker/api/decorators/pact_versions_decorator.rb +1 -2
- data/lib/pact_broker/api/decorators/pact_webhooks_status_decorator.rb +123 -0
- data/lib/pact_broker/api/decorators/versions_decorator.rb +17 -6
- data/lib/pact_broker/api/decorators/webhook_decorator.rb +8 -10
- data/lib/pact_broker/api/decorators/webhooks_decorator.rb +0 -1
- data/lib/pact_broker/api/pact_broker_urls.rb +13 -1
- data/lib/pact_broker/api/renderers/html_pact_renderer.rb +47 -3
- data/lib/pact_broker/api/resources/badge.rb +3 -3
- data/lib/pact_broker/api/resources/base_resource.rb +1 -1
- data/lib/pact_broker/api/resources/latest_pact.rb +5 -1
- data/lib/pact_broker/api/resources/pact.rb +5 -1
- data/lib/pact_broker/api/resources/pact_webhooks_status.rb +61 -0
- data/lib/pact_broker/api/resources/triggered_webhook_logs.rb +36 -0
- data/lib/pact_broker/api/resources/webhook.rb +31 -3
- data/lib/pact_broker/api/resources/webhook_execution.rb +12 -2
- data/lib/pact_broker/api.rb +3 -0
- data/lib/pact_broker/app.rb +11 -3
- data/lib/pact_broker/badges/service.rb +26 -5
- data/lib/pact_broker/configuration.rb +12 -5
- data/lib/pact_broker/constants.rb +1 -1
- data/lib/pact_broker/diagnostic/resources/heartbeat.rb +1 -2
- data/lib/pact_broker/doc/views/pact-webhooks.markdown +1 -1
- data/lib/pact_broker/doc/views/webhooks-webhooks.markdown +1 -1
- data/lib/pact_broker/doc/views/webhooks.markdown +1 -1
- data/lib/pact_broker/domain/relationship.rb +13 -4
- data/lib/pact_broker/domain/verification.rb +0 -4
- data/lib/pact_broker/domain/webhook.rb +2 -6
- data/lib/pact_broker/domain/webhook_execution_result.rb +1 -2
- data/lib/pact_broker/domain/webhook_request.rb +59 -40
- data/lib/pact_broker/pacticipants/service.rb +4 -3
- data/lib/pact_broker/pacts/repository.rb +8 -0
- data/lib/pact_broker/pacts/service.rb +2 -0
- data/lib/pact_broker/services.rb +1 -1
- data/lib/pact_broker/ui/view_models/relationship.rb +29 -2
- data/lib/pact_broker/ui/views/relationships/show.haml +7 -10
- data/lib/pact_broker/verifications/repository.rb +8 -1
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/webhooks/execution.rb +25 -4
- data/lib/pact_broker/webhooks/job.rb +55 -13
- data/lib/pact_broker/webhooks/latest_triggered_webhook.rb +9 -0
- data/lib/pact_broker/webhooks/redact_logs.rb +10 -0
- data/lib/pact_broker/webhooks/repository.rb +76 -8
- data/lib/pact_broker/webhooks/service.rb +48 -8
- data/lib/pact_broker/webhooks/status.rb +29 -0
- data/lib/pact_broker/webhooks/triggered_webhook.rb +96 -0
- data/lib/pact_broker/webhooks/webhook.rb +19 -8
- data/lib/rack/pact_broker/database_transaction.rb +9 -3
- data/pact_broker.gemspec +3 -3
- data/public/javascripts/pact.js +5 -0
- data/public/stylesheets/pact.css +14 -1
- data/public/stylesheets/relationships.css +0 -1
- data/script/db-spec.sh +7 -0
- data/script/seed.rb +13 -8
- data/spec/features/create_webhook_spec.rb +1 -1
- data/spec/features/delete_pact_spec.rb +5 -1
- data/spec/features/delete_webhook_spec.rb +2 -1
- data/spec/features/edit_webhook_spec.rb +61 -0
- data/spec/features/execute_webhook_spec.rb +73 -0
- data/spec/features/get_latest_pact_badge_spec.rb +1 -1
- data/spec/features/get_latest_tagged_pact_badge_spec.rb +1 -1
- data/spec/features/get_latest_untagged_pact_badge_spec.rb +1 -1
- data/spec/features/get_pact_spec.rb +1 -1
- data/spec/features/merge_pact_spec.rb +1 -1
- data/spec/features/publish_pact_spec.rb +1 -1
- data/spec/integration/app_spec.rb +1 -1
- data/spec/integration/endpoints/group.rb +1 -1
- data/spec/lib/pact_broker/api/decorators/latest_pact_decorator_spec.rb +2 -1
- data/spec/lib/pact_broker/api/decorators/pact_decorator_spec.rb +8 -6
- data/spec/lib/pact_broker/api/decorators/pact_webhooks_status_decorator_spec.rb +134 -0
- data/spec/lib/pact_broker/api/decorators/relationships_csv_decorator_spec.rb +1 -1
- data/spec/lib/pact_broker/api/decorators/representable_pact_spec.rb +1 -1
- data/spec/lib/pact_broker/api/renderers/html_pact_renderer_spec.rb +27 -1
- data/spec/lib/pact_broker/api/resources/badge_spec.rb +32 -15
- data/spec/lib/pact_broker/api/resources/base_resource_spec.rb +17 -0
- data/spec/lib/pact_broker/api/resources/latest_pact_spec.rb +5 -3
- data/spec/lib/pact_broker/api/resources/pact_spec.rb +9 -2
- data/spec/lib/pact_broker/api/resources/triggered_webhook_logs_spec.rb +28 -0
- data/spec/lib/pact_broker/api/resources/webhook_execution_spec.rb +15 -5
- data/spec/lib/pact_broker/api/resources/webhook_spec.rb +43 -31
- data/spec/lib/pact_broker/app_spec.rb +12 -8
- data/spec/lib/pact_broker/badges/service_spec.rb +15 -1
- data/spec/lib/pact_broker/configuration_spec.rb +3 -2
- data/spec/lib/pact_broker/domain/relationship_spec.rb +24 -0
- data/spec/lib/pact_broker/domain/webhook_request_spec.rb +47 -31
- data/spec/lib/pact_broker/domain/webhook_spec.rb +4 -6
- data/spec/lib/pact_broker/pacticipants/service_spec.rb +16 -1
- data/spec/lib/pact_broker/pacts/repository_spec.rb +22 -1
- data/spec/lib/pact_broker/pacts/service_spec.rb +32 -1
- data/spec/lib/pact_broker/ui/view_models/relationship_spec.rb +44 -0
- data/spec/lib/pact_broker/verifications/repository_spec.rb +19 -0
- data/spec/lib/pact_broker/verifications/service_spec.rb +1 -1
- data/spec/lib/pact_broker/webhooks/job_spec.rb +80 -19
- data/spec/lib/pact_broker/webhooks/redact_logs_spec.rb +49 -0
- data/spec/lib/pact_broker/webhooks/repository_spec.rb +271 -21
- data/spec/lib/pact_broker/webhooks/service_spec.rb +70 -3
- data/spec/lib/pact_broker/webhooks/status_spec.rb +48 -0
- data/spec/lib/pact_broker/webhooks/triggered_webhook_spec.rb +40 -0
- data/spec/lib/rack/pact_broker/database_transaction_spec.rb +14 -4
- data/spec/migrations/23_pact_versions_spec.rb +8 -30
- data/spec/migrations/24_populate_pact_contents_spec.rb +3 -21
- data/spec/migrations/34_latest_tagged_pacts_spec.rb +1 -17
- data/spec/migrations/34_pact_revisions_spec.rb +7 -23
- data/spec/migrations/41_migrate_execution_data_spec.rb +109 -0
- data/spec/service_consumers/pact_helper.rb +5 -1
- data/spec/spec_helper.rb +15 -7
- data/spec/support/database_cleaner.rb +15 -2
- data/spec/support/migration_helpers.rb +16 -0
- data/spec/support/test_data_builder.rb +41 -9
- data/tasks/database.rb +7 -2
- data/tasks/db.rake +10 -0
- data/tasks/rspec.rake +1 -1
- data/vendor/hal-browser/browser.html +3 -2
- data/vendor/hal-browser/js/hal/resource.js +16 -2
- metadata +72 -13
- data/script/record_verification.sh +0 -4
@@ -3,6 +3,7 @@ require 'pact_broker/domain/webhook_execution_result'
|
|
3
3
|
require 'pact_broker/logging'
|
4
4
|
require 'pact_broker/messages'
|
5
5
|
require 'net/http'
|
6
|
+
require 'pact_broker/webhooks/redact_logs'
|
6
7
|
|
7
8
|
module PactBroker
|
8
9
|
|
@@ -46,60 +47,80 @@ module PactBroker
|
|
46
47
|
password.nil? ? nil : "**********"
|
47
48
|
end
|
48
49
|
|
49
|
-
def execute
|
50
|
-
|
50
|
+
def execute options = {}
|
51
51
|
logs = StringIO.new
|
52
52
|
execution_logger = Logger.new(logs)
|
53
|
-
|
54
53
|
begin
|
55
|
-
|
56
|
-
|
54
|
+
execute_and_build_result(options, logs, execution_logger)
|
55
|
+
rescue StandardError => e
|
56
|
+
handle_error_and_build_result(e, options, logs, execution_logger)
|
57
|
+
end
|
58
|
+
end
|
57
59
|
|
58
|
-
|
59
|
-
execution_logger.info "#{name}: #{value}"
|
60
|
-
req[name] = value
|
61
|
-
end
|
60
|
+
private
|
62
61
|
|
63
|
-
|
62
|
+
def execute_and_build_result options, logs, execution_logger
|
63
|
+
req = build_request(execution_logger)
|
64
|
+
response = do_request(req)
|
65
|
+
log_response(response, execution_logger)
|
66
|
+
result = WebhookExecutionResult.new(response, logs.string)
|
67
|
+
log_completion_message(options, execution_logger, result.success?)
|
68
|
+
result
|
69
|
+
end
|
64
70
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
71
|
+
def handle_error_and_build_result e, options, logs, execution_logger
|
72
|
+
logger.error "Error executing webhook #{uuid} #{e.class.name} - #{e.message} #{e.backtrace.join("\n")}"
|
73
|
+
execution_logger.error "Error executing webhook #{uuid} #{e.class.name} - #{e.message}"
|
74
|
+
log_completion_message(options, execution_logger, false)
|
75
|
+
WebhookExecutionResult.new(nil, logs.string, e)
|
76
|
+
end
|
77
|
+
|
78
|
+
def build_request execution_logger
|
79
|
+
req = http_request
|
80
|
+
execution_logger.info "HTTP/1.1 #{method.upcase} #{url_with_credentials}"
|
72
81
|
|
73
|
-
|
82
|
+
headers.each_pair do | name, value |
|
83
|
+
execution_logger.info Webhooks::RedactLogs.call("#{name}: #{value}")
|
84
|
+
req[name] = value
|
85
|
+
end
|
74
86
|
|
75
|
-
|
87
|
+
req.basic_auth(username, password) if username
|
76
88
|
|
77
|
-
|
78
|
-
|
79
|
-
|
89
|
+
unless body.nil?
|
90
|
+
if String === body
|
91
|
+
req.body = body
|
92
|
+
else
|
93
|
+
req.body = body.to_json
|
80
94
|
end
|
95
|
+
end
|
81
96
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
response.each_header do | header |
|
86
|
-
execution_logger.info "#{header.split("-").collect(&:capitalize).join('-')}: #{response[header]}"
|
87
|
-
end
|
88
|
-
logger.debug "body=#{response.body}"
|
89
|
-
execution_logger.info response.body
|
90
|
-
WebhookExecutionResult.new(response, logs.string)
|
97
|
+
execution_logger.info req.body
|
98
|
+
req
|
99
|
+
end
|
91
100
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
WebhookExecutionResult.new(nil, logs.string, e)
|
101
|
+
def do_request req
|
102
|
+
logger.info "Making webhook #{uuid} request #{to_s}"
|
103
|
+
Net::HTTP.start(uri.hostname, uri.port,
|
104
|
+
:use_ssl => uri.scheme == 'https') do |http|
|
105
|
+
http.request req
|
98
106
|
end
|
107
|
+
end
|
99
108
|
|
109
|
+
def log_response response, execution_logger
|
110
|
+
execution_logger.info(" ")
|
111
|
+
logger.info "Received response for webhook #{uuid} status=#{response.code}"
|
112
|
+
execution_logger.info "HTTP/#{response.http_version} #{response.code} #{response.message}"
|
113
|
+
response.each_header do | header |
|
114
|
+
execution_logger.info "#{header.split("-").collect(&:capitalize).join('-')}: #{response[header]}"
|
115
|
+
end
|
116
|
+
logger.debug "body=#{response.body}"
|
117
|
+
execution_logger.info response.body
|
100
118
|
end
|
101
119
|
|
102
|
-
|
120
|
+
def log_completion_message options, execution_logger, success
|
121
|
+
execution_logger.info(options[:success_log_message]) if options[:success_log_message] && success
|
122
|
+
execution_logger.info(options[:failure_log_message]) if options[:failure_log_message] && !success
|
123
|
+
end
|
103
124
|
|
104
125
|
def to_s
|
105
126
|
"#{method.upcase} #{url}, username=#{username}, password=#{display_password}, headers=#{headers}, body=#{body}"
|
@@ -119,7 +140,5 @@ module PactBroker
|
|
119
140
|
u
|
120
141
|
end
|
121
142
|
end
|
122
|
-
|
123
143
|
end
|
124
|
-
|
125
144
|
end
|
@@ -58,12 +58,14 @@ module PactBroker
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
+
# This needs to move into a new service
|
61
62
|
def self.find_relationships
|
62
63
|
pact_repository.find_latest_pacts
|
63
64
|
.collect do | pact|
|
64
65
|
latest_verification = verification_service.find_latest_verification_for(pact.consumer, pact.provider)
|
65
66
|
webhooks = webhook_service.find_by_consumer_and_provider pact.consumer, pact.provider
|
66
|
-
|
67
|
+
triggered_webhooks = webhook_service.find_latest_triggered_webhooks pact.consumer, pact.provider
|
68
|
+
PactBroker::Domain::Relationship.create pact.consumer, pact.provider, pact, latest_verification, webhooks, triggered_webhooks
|
67
69
|
end
|
68
70
|
end
|
69
71
|
|
@@ -83,7 +85,7 @@ module PactBroker
|
|
83
85
|
version_ids = PactBroker::Domain::Version.where(pacticipant_id: pacticipant.id).select_for_subquery(:id) #stupid mysql doesn't allow subqueries
|
84
86
|
select_pacticipant = "select id from pacticipants where name = '#{name}'"
|
85
87
|
tag_repository.delete_by_version_id version_ids
|
86
|
-
|
88
|
+
webhook_service.delete_all_webhhook_related_objects_by_pacticipant pacticipant
|
87
89
|
pact_repository.delete_by_version_id version_ids
|
88
90
|
connection.run("delete from pact_publications where provider_id = #{pacticipant.id}")
|
89
91
|
connection.run("delete from verifications where pact_version_id IN (select id from pact_versions where provider_id = #{pacticipant.id})")
|
@@ -92,7 +94,6 @@ module PactBroker
|
|
92
94
|
connection.run("delete from pact_versions where consumer_id = #{pacticipant.id}")
|
93
95
|
connection.run("delete from versions where pacticipant_id = #{pacticipant.id}")
|
94
96
|
version_repository.delete_by_id version_ids
|
95
|
-
webhook_service.delete_by_pacticipant pacticipant
|
96
97
|
connection.run("delete from pacticipants where id = #{pacticipant.id}")
|
97
98
|
end
|
98
99
|
|
@@ -112,6 +112,14 @@ module PactBroker
|
|
112
112
|
query.limit(1).collect(&:to_domain_with_content)[0]
|
113
113
|
end
|
114
114
|
|
115
|
+
def find_all_revisions consumer_name, consumer_version, provider_name
|
116
|
+
AllPactPublications
|
117
|
+
.consumer(consumer_name)
|
118
|
+
.provider(provider_name)
|
119
|
+
.consumer_version_number(consumer_version)
|
120
|
+
.order(:consumer_version_order, :revision_number).collect(&:to_domain_with_content)
|
121
|
+
end
|
122
|
+
|
115
123
|
def find_previous_pact pact
|
116
124
|
LatestPactPublicationsByConsumerVersion
|
117
125
|
.eager(:tags)
|
@@ -31,6 +31,8 @@ module PactBroker
|
|
31
31
|
|
32
32
|
def delete params
|
33
33
|
logger.info "Deleting pact version with params #{params}"
|
34
|
+
pacts = pact_repository.find_all_revisions(params[:consumer_name], params[:consumer_version_number], params[:provider_name])
|
35
|
+
webhook_service.delete_all_webhook_related_objects_by_pact_publication_ids(pacts.collect(&:id))
|
34
36
|
pact_repository.delete(params)
|
35
37
|
end
|
36
38
|
|
data/lib/pact_broker/services.rb
CHANGED
@@ -37,8 +37,35 @@ module PactBroker
|
|
37
37
|
@relationship.any_webhooks?
|
38
38
|
end
|
39
39
|
|
40
|
-
def
|
41
|
-
|
40
|
+
def webhook_label
|
41
|
+
case @relationship.webhook_status
|
42
|
+
when :none then "Create"
|
43
|
+
when :success, :failure then webhook_last_execution_date
|
44
|
+
when :retrying then "Retrying"
|
45
|
+
when :not_run then "Not run"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def webhook_status
|
50
|
+
case @relationship.webhook_status
|
51
|
+
when :success then "success"
|
52
|
+
when :failure then "danger"
|
53
|
+
when :retrying then "warning"
|
54
|
+
else ""
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def webhook_last_execution_date
|
59
|
+
PactBroker::DateHelper.distance_of_time_in_words(@relationship.last_webhook_execution_date, DateTime.now) + " ago"
|
60
|
+
end
|
61
|
+
|
62
|
+
def webhook_url
|
63
|
+
url = case @relationship.webhook_status
|
64
|
+
when :none
|
65
|
+
PactBroker::Api::PactBrokerUrls.webhooks_for_pact_url @relationship.latest_pact.consumer, @relationship.latest_pact.provider
|
66
|
+
else
|
67
|
+
PactBroker::Api::PactBrokerUrls.webhooks_status_url @relationship.latest_pact.consumer, @relationship.latest_pact.provider
|
68
|
+
end
|
42
69
|
"/hal-browser/browser.html##{url}"
|
43
70
|
end
|
44
71
|
|
@@ -26,11 +26,11 @@
|
|
26
26
|
%span.glyphicon.glyphicon-sort.relationships-sort
|
27
27
|
%th
|
28
28
|
%th
|
29
|
-
Latest pact
|
29
|
+
Latest pact<br>published
|
30
30
|
%th
|
31
|
-
|
31
|
+
Webhook<br>status
|
32
32
|
%th
|
33
|
-
Last
|
33
|
+
Last<br>verified
|
34
34
|
%tbody
|
35
35
|
|
36
36
|
- relationships.each do | relationship |
|
@@ -48,13 +48,10 @@
|
|
48
48
|
%td
|
49
49
|
%td
|
50
50
|
= relationship.publication_date_of_latest_pact
|
51
|
-
%td
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
- else
|
56
|
-
%a{:href => relationship.webhooks_url}
|
57
|
-
Create
|
51
|
+
%td{class: relationship.webhook_status}
|
52
|
+
%a{:href => relationship.webhook_url}
|
53
|
+
= relationship.webhook_label
|
54
|
+
|
58
55
|
%td{class: relationship.verification_status, title: relationship.verification_tooltip, "data-toggle": "tooltip", "data-placement": "left"}
|
59
56
|
%div
|
60
57
|
= relationship.last_verified_date
|
@@ -19,6 +19,7 @@ module PactBroker
|
|
19
19
|
|
20
20
|
def find consumer_name, provider_name, pact_version_sha, verification_number
|
21
21
|
PactBroker::Domain::Verification
|
22
|
+
.select_all_qualified
|
22
23
|
.join(:all_pact_publications, pact_version_id: :pact_version_id)
|
23
24
|
.consumer(consumer_name)
|
24
25
|
.provider(provider_name)
|
@@ -30,6 +31,7 @@ module PactBroker
|
|
30
31
|
# Use LatestPactPublicationsByConsumerVersion not AllPactPublcations because we don't
|
31
32
|
# want verifications for shadowed revisions as it would be misleading.
|
32
33
|
LatestVerificationsByConsumerVersion
|
34
|
+
.select_all_qualified
|
33
35
|
.join(:latest_pact_publications_by_consumer_versions, pact_version_id: :pact_version_id)
|
34
36
|
.consumer(consumer_name)
|
35
37
|
.consumer_version_number(consumer_version_number)
|
@@ -39,6 +41,7 @@ module PactBroker
|
|
39
41
|
|
40
42
|
def find_latest_verification_for consumer_name, provider_name, tag = nil
|
41
43
|
query = LatestVerificationsByConsumerVersion
|
44
|
+
.select_all_qualified
|
42
45
|
.join(:all_pact_publications, pact_version_id: :pact_version_id)
|
43
46
|
.consumer(consumer_name)
|
44
47
|
.provider(provider_name)
|
@@ -47,7 +50,11 @@ module PactBroker
|
|
47
50
|
elsif tag
|
48
51
|
query = query.tag(tag)
|
49
52
|
end
|
50
|
-
query.
|
53
|
+
query.reverse_order(
|
54
|
+
Sequel[:all_pact_publications][:consumer_version_order],
|
55
|
+
Sequel[:all_pact_publications][:revision_number],
|
56
|
+
Sequel[LatestVerificationsByConsumerVersion.table_name][:number]
|
57
|
+
).limit(1).single_record
|
51
58
|
end
|
52
59
|
|
53
60
|
def pact_version_id_for pact
|
data/lib/pact_broker/version.rb
CHANGED
@@ -1,14 +1,35 @@
|
|
1
1
|
require 'sequel'
|
2
|
+
require 'pact_broker/db'
|
3
|
+
require 'pact_broker/repositories/helpers'
|
4
|
+
|
2
5
|
|
3
6
|
module PactBroker
|
4
7
|
module Webhooks
|
5
|
-
class Execution < Sequel::Model(
|
8
|
+
class Execution < Sequel::Model(
|
9
|
+
PactBroker::DB.connection[:webhook_executions].select(
|
10
|
+
Sequel[:webhook_executions][:id],
|
11
|
+
:triggered_webhook_id,
|
12
|
+
:success,
|
13
|
+
:logs,
|
14
|
+
Sequel[:webhook_executions][:created_at])
|
15
|
+
)
|
16
|
+
|
17
|
+
dataset_module do
|
18
|
+
include PactBroker::Repositories::Helpers
|
19
|
+
end
|
20
|
+
|
21
|
+
associate(:many_to_one, :triggered_webhook, :class => "PactBroker::Webhooks::TriggeredWebhook", :key => :triggered_webhook_id, :primary_key => :id)
|
6
22
|
|
7
|
-
|
8
|
-
|
23
|
+
def <=> other
|
24
|
+
comp = created_date <=> other.created_date
|
25
|
+
comp = id <=> other.id if comp == 0
|
26
|
+
comp
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class DeprecatedExecution < Sequel::Model(:webhook_executions)
|
9
31
|
associate(:many_to_one, :provider, :class => "PactBroker::Domain::Pacticipant", :key => :provider_id, :primary_key => :id)
|
10
32
|
associate(:many_to_one, :consumer, :class => "PactBroker::Domain::Pacticipant", :key => :consumer_id, :primary_key => :id)
|
11
|
-
|
12
33
|
end
|
13
34
|
|
14
35
|
Execution.plugin :timestamps
|
@@ -6,17 +6,20 @@ module PactBroker
|
|
6
6
|
module Webhooks
|
7
7
|
class Job
|
8
8
|
|
9
|
-
BACKOFF_TIMES = [10, 60, 120, 300, 600, 1200] #10 sec, 1 min, 2 min, 5 min, 10 min, 20 min => 38 minutes
|
10
|
-
|
11
9
|
include SuckerPunch::Job
|
12
10
|
include PactBroker::Logging
|
13
11
|
|
14
12
|
def perform data
|
15
|
-
@
|
13
|
+
@data = data
|
14
|
+
@triggered_webhook = data[:triggered_webhook]
|
16
15
|
@error_count = data[:error_count] || 0
|
17
16
|
begin
|
18
|
-
webhook_execution_result = PactBroker::Webhooks::Service.
|
19
|
-
|
17
|
+
webhook_execution_result = PactBroker::Webhooks::Service.execute_triggered_webhook_now triggered_webhook, execution_options
|
18
|
+
if webhook_execution_result.success?
|
19
|
+
handle_success
|
20
|
+
else
|
21
|
+
handle_failure
|
22
|
+
end
|
20
23
|
rescue StandardError => e
|
21
24
|
handle_error e
|
22
25
|
end
|
@@ -24,23 +27,62 @@ module PactBroker
|
|
24
27
|
|
25
28
|
private
|
26
29
|
|
27
|
-
attr_reader :
|
30
|
+
attr_reader :triggered_webhook, :error_count
|
31
|
+
|
32
|
+
def execution_options
|
33
|
+
{
|
34
|
+
success_log_message: "Successfully executed webhook",
|
35
|
+
failure_log_message: failure_log_message
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def failure_log_message
|
40
|
+
if reschedule_job?
|
41
|
+
"Retrying webhook in #{backoff_time} seconds"
|
42
|
+
else
|
43
|
+
"Webhook execution failed after #{retry_schedule.size + 1} attempts"
|
44
|
+
end
|
45
|
+
end
|
28
46
|
|
29
47
|
def handle_error e
|
30
48
|
log_error e
|
31
|
-
|
49
|
+
handle_failure
|
32
50
|
end
|
33
51
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
52
|
+
def handle_success
|
53
|
+
update_triggered_webhook_status TriggeredWebhook::STATUS_SUCCESS
|
54
|
+
end
|
55
|
+
|
56
|
+
def handle_failure
|
57
|
+
if reschedule_job?
|
58
|
+
reschedule_job
|
59
|
+
update_triggered_webhook_status TriggeredWebhook::STATUS_RETRYING
|
39
60
|
else
|
40
|
-
logger.error "Failed to execute webhook #{
|
61
|
+
logger.error "Failed to execute webhook #{triggered_webhook.webhook_uuid} after #{retry_schedule.size + 1} attempts."
|
62
|
+
update_triggered_webhook_status TriggeredWebhook::STATUS_FAILURE
|
41
63
|
end
|
42
64
|
end
|
43
65
|
|
66
|
+
def reschedule_job?
|
67
|
+
error_count < retry_schedule.size
|
68
|
+
end
|
69
|
+
|
70
|
+
def reschedule_job
|
71
|
+
logger.debug "Re-enqeuing job for webhook #{triggered_webhook.webhook_uuid} to run in #{backoff_time} seconds"
|
72
|
+
Job.perform_in(backoff_time, @data.merge(error_count: error_count+1))
|
73
|
+
end
|
74
|
+
|
75
|
+
def update_triggered_webhook_status status
|
76
|
+
PactBroker::Webhooks::Service.update_triggered_webhook_status triggered_webhook, status
|
77
|
+
end
|
78
|
+
|
79
|
+
def backoff_time
|
80
|
+
retry_schedule[error_count]
|
81
|
+
end
|
82
|
+
|
83
|
+
def retry_schedule
|
84
|
+
PactBroker.configuration.webhook_retry_schedule
|
85
|
+
end
|
44
86
|
end
|
45
87
|
end
|
46
88
|
end
|
@@ -3,6 +3,8 @@ require 'pact_broker/domain/webhook'
|
|
3
3
|
require 'pact_broker/domain/pacticipant'
|
4
4
|
require 'pact_broker/db'
|
5
5
|
require 'pact_broker/webhooks/webhook'
|
6
|
+
require 'pact_broker/webhooks/triggered_webhook'
|
7
|
+
require 'pact_broker/webhooks/latest_triggered_webhook'
|
6
8
|
require 'pact_broker/webhooks/execution'
|
7
9
|
|
8
10
|
module PactBroker
|
@@ -26,6 +28,16 @@ module PactBroker
|
|
26
28
|
Webhook.where(uuid: uuid).limit(1).collect(&:to_domain)[0]
|
27
29
|
end
|
28
30
|
|
31
|
+
def update_by_uuid uuid, webhook
|
32
|
+
existing_webhook = Webhook.find(uuid: uuid)
|
33
|
+
existing_webhook.update_from_domain(webhook).save
|
34
|
+
existing_webhook.headers.collect(&:delete)
|
35
|
+
webhook.request.headers.each_pair do | name, value |
|
36
|
+
existing_webhook.add_header PactBroker::Webhooks::WebhookHeader.from_domain(name, value, existing_webhook.id)
|
37
|
+
end
|
38
|
+
find_by_uuid uuid
|
39
|
+
end
|
40
|
+
|
29
41
|
def delete_by_uuid uuid
|
30
42
|
Webhook.where(uuid: uuid).destroy
|
31
43
|
end
|
@@ -43,23 +55,79 @@ module PactBroker
|
|
43
55
|
Webhook.where(consumer_id: consumer.id, provider_id: provider.id).collect(&:to_domain)
|
44
56
|
end
|
45
57
|
|
46
|
-
def
|
58
|
+
def find_by_consumer_and_provider_existing_at consumer, provider, date_time
|
59
|
+
Webhook.where(consumer_id: consumer.id, provider_id: provider.id)
|
60
|
+
.where(Sequel.lit("created_at < ?", date_time))
|
61
|
+
.collect(&:to_domain)
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_triggered_webhook trigger_uuid, webhook, pact, trigger_type
|
47
65
|
db_webhook = Webhook.where(uuid: webhook.uuid).single_record
|
48
|
-
|
66
|
+
TriggeredWebhook.create(
|
67
|
+
status: TriggeredWebhook::STATUS_NOT_RUN,
|
68
|
+
pact_publication_id: pact.id,
|
49
69
|
webhook: db_webhook,
|
70
|
+
webhook_uuid: db_webhook.uuid,
|
71
|
+
trigger_uuid: trigger_uuid,
|
72
|
+
trigger_type: trigger_type,
|
50
73
|
consumer: db_webhook.consumer,
|
51
|
-
provider: db_webhook.provider
|
74
|
+
provider: db_webhook.provider
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
def update_triggered_webhook_status triggered_webhook, status
|
79
|
+
triggered_webhook.update(status: status)
|
80
|
+
end
|
81
|
+
|
82
|
+
def create_execution triggered_webhook, webhook_execution_result
|
83
|
+
Execution.create(
|
84
|
+
triggered_webhook: triggered_webhook,
|
52
85
|
success: webhook_execution_result.success?,
|
53
86
|
logs: webhook_execution_result.logs)
|
54
87
|
end
|
55
88
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
89
|
+
def delete_triggered_webhooks_by_pacticipant pacticipant
|
90
|
+
TriggeredWebhook.where(consumer: pacticipant).delete
|
91
|
+
TriggeredWebhook.where(provider: pacticipant).delete
|
92
|
+
end
|
93
|
+
|
94
|
+
def delete_executions_by_pacticipant pacticipants
|
95
|
+
# TODO this relationship no longer exists, deprecate in next version
|
96
|
+
DeprecatedExecution.where(consumer: pacticipants).delete
|
97
|
+
DeprecatedExecution.where(provider: pacticipants).delete
|
98
|
+
execution_ids = Execution
|
99
|
+
.join(:triggered_webhooks, {id: :triggered_webhook_id})
|
100
|
+
.where(Sequel.or(
|
101
|
+
Sequel[:triggered_webhooks][:consumer_id] => [*pacticipants].collect(&:id),
|
102
|
+
Sequel[:triggered_webhooks][:provider_id] => [*pacticipants].collect(&:id),
|
103
|
+
)).all.collect(&:id)
|
104
|
+
Execution.where(id: execution_ids).delete
|
105
|
+
end
|
106
|
+
|
107
|
+
def unlink_triggered_webhooks_by_webhook_uuid uuid
|
108
|
+
TriggeredWebhook.where(webhook: Webhook.where(uuid: uuid)).update(webhook_id: nil)
|
109
|
+
DeprecatedExecution.where(webhook_id: Webhook.where(uuid: uuid).select(:id)).update(webhook_id: nil)
|
110
|
+
end
|
111
|
+
|
112
|
+
def delete_triggered_webhooks_by_pact_publication_ids pact_publication_ids
|
113
|
+
triggered_webhook_ids = TriggeredWebhook.where(pact_publication_id: pact_publication_ids).select_for_subquery(:id)
|
114
|
+
Execution.where(triggered_webhook_id: triggered_webhook_ids).delete
|
115
|
+
TriggeredWebhook.where(id: triggered_webhook_ids).delete
|
116
|
+
DeprecatedExecution.where(pact_publication_id: pact_publication_ids).delete
|
117
|
+
end
|
118
|
+
|
119
|
+
def find_latest_triggered_webhooks consumer, provider
|
120
|
+
LatestTriggeredWebhook
|
121
|
+
.where(consumer: consumer, provider: provider)
|
122
|
+
.order(:id)
|
123
|
+
.all
|
124
|
+
.group_by{|w| [w.consumer_id, w.provider_id, w.webhook_uuid]}
|
125
|
+
.values
|
126
|
+
.collect(&:last)
|
59
127
|
end
|
60
128
|
|
61
|
-
def
|
62
|
-
|
129
|
+
def fail_retrying_triggered_webhooks
|
130
|
+
TriggeredWebhook.retrying.update(status: TriggeredWebhook::STATUS_FAILURE)
|
63
131
|
end
|
64
132
|
end
|
65
133
|
end
|