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.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis.yml +4 -2
  4. data/CHANGELOG.md +54 -0
  5. data/DEVELOPER_DOCUMENTATION.md +11 -7
  6. data/README.md +5 -1
  7. data/UPGRADING.md +18 -0
  8. data/db/migrations/19_make_pact_version_content_sha_not_nullable.rb +9 -1
  9. data/db/migrations/25_make_pv_pacticipants_mandatory.rb +8 -0
  10. data/db/migrations/38_create_triggered_webhooks_table.rb +19 -0
  11. data/db/migrations/39_add_triggered_webhooks_fk_to_execution.rb +24 -0
  12. data/db/migrations/40_create_latest_triggered_webhooks_view.rb +24 -0
  13. data/db/migrations/41_migrate_execution_data.rb +47 -0
  14. data/db/test/backwards_compatibility/.rspec +3 -0
  15. data/db/test/backwards_compatibility/Appraisals +49 -0
  16. data/db/test/backwards_compatibility/Gemfile +11 -0
  17. data/db/test/backwards_compatibility/Rakefile +55 -0
  18. data/db/test/backwards_compatibility/config.ru +18 -0
  19. data/db/test/backwards_compatibility/gemfiles/1.18.0.gemfile +14 -0
  20. data/db/test/backwards_compatibility/gemfiles/1.18.0.gemfile.lock +210 -0
  21. data/db/test/backwards_compatibility/gemfiles/2.0.0.gemfile +14 -0
  22. data/db/test/backwards_compatibility/gemfiles/2.0.0.gemfile.lock +208 -0
  23. data/db/test/backwards_compatibility/gemfiles/2.1.0.gemfile +14 -0
  24. data/db/test/backwards_compatibility/gemfiles/2.1.0.gemfile.lock +209 -0
  25. data/db/test/backwards_compatibility/gemfiles/2.2.0.gemfile +14 -0
  26. data/db/test/backwards_compatibility/gemfiles/2.2.0.gemfile.lock +197 -0
  27. data/db/test/backwards_compatibility/gemfiles/2.3.0.gemfile +13 -0
  28. data/db/test/backwards_compatibility/gemfiles/2.3.0.gemfile.lock +196 -0
  29. data/db/test/backwards_compatibility/gemfiles/2.4.2.gemfile +13 -0
  30. data/db/test/backwards_compatibility/gemfiles/2.4.2.gemfile.lock +196 -0
  31. data/db/test/backwards_compatibility/gemfiles/head.gemfile +13 -0
  32. data/db/test/backwards_compatibility/gemfiles/head.gemfile.lock +200 -0
  33. data/db/test/backwards_compatibility/spec/fixtures/foo-bar.json +22 -0
  34. data/db/test/backwards_compatibility/spec/publish_pact_spec.rb +72 -0
  35. data/db/test/backwards_compatibility/spec/spec_helper.rb +20 -0
  36. data/db/test/backwards_compatibility/spec/support/fixture_helpers.rb +12 -0
  37. data/db/test/backwards_compatibility/spec/support/request_helpers.rb +20 -0
  38. data/example/Gemfile +2 -2
  39. data/example/pact_broker_database.sqlite3 +0 -0
  40. data/lib/pact_broker/api/decorators/pact_collection_decorator.rb +1 -2
  41. data/lib/pact_broker/api/decorators/pact_decorator.rb +12 -10
  42. data/lib/pact_broker/api/decorators/pact_versions_decorator.rb +1 -2
  43. data/lib/pact_broker/api/decorators/pact_webhooks_status_decorator.rb +123 -0
  44. data/lib/pact_broker/api/decorators/versions_decorator.rb +17 -6
  45. data/lib/pact_broker/api/decorators/webhook_decorator.rb +8 -10
  46. data/lib/pact_broker/api/decorators/webhooks_decorator.rb +0 -1
  47. data/lib/pact_broker/api/pact_broker_urls.rb +13 -1
  48. data/lib/pact_broker/api/renderers/html_pact_renderer.rb +47 -3
  49. data/lib/pact_broker/api/resources/badge.rb +3 -3
  50. data/lib/pact_broker/api/resources/base_resource.rb +1 -1
  51. data/lib/pact_broker/api/resources/latest_pact.rb +5 -1
  52. data/lib/pact_broker/api/resources/pact.rb +5 -1
  53. data/lib/pact_broker/api/resources/pact_webhooks_status.rb +61 -0
  54. data/lib/pact_broker/api/resources/triggered_webhook_logs.rb +36 -0
  55. data/lib/pact_broker/api/resources/webhook.rb +31 -3
  56. data/lib/pact_broker/api/resources/webhook_execution.rb +12 -2
  57. data/lib/pact_broker/api.rb +3 -0
  58. data/lib/pact_broker/app.rb +11 -3
  59. data/lib/pact_broker/badges/service.rb +26 -5
  60. data/lib/pact_broker/configuration.rb +12 -5
  61. data/lib/pact_broker/constants.rb +1 -1
  62. data/lib/pact_broker/diagnostic/resources/heartbeat.rb +1 -2
  63. data/lib/pact_broker/doc/views/pact-webhooks.markdown +1 -1
  64. data/lib/pact_broker/doc/views/webhooks-webhooks.markdown +1 -1
  65. data/lib/pact_broker/doc/views/webhooks.markdown +1 -1
  66. data/lib/pact_broker/domain/relationship.rb +13 -4
  67. data/lib/pact_broker/domain/verification.rb +0 -4
  68. data/lib/pact_broker/domain/webhook.rb +2 -6
  69. data/lib/pact_broker/domain/webhook_execution_result.rb +1 -2
  70. data/lib/pact_broker/domain/webhook_request.rb +59 -40
  71. data/lib/pact_broker/pacticipants/service.rb +4 -3
  72. data/lib/pact_broker/pacts/repository.rb +8 -0
  73. data/lib/pact_broker/pacts/service.rb +2 -0
  74. data/lib/pact_broker/services.rb +1 -1
  75. data/lib/pact_broker/ui/view_models/relationship.rb +29 -2
  76. data/lib/pact_broker/ui/views/relationships/show.haml +7 -10
  77. data/lib/pact_broker/verifications/repository.rb +8 -1
  78. data/lib/pact_broker/version.rb +1 -1
  79. data/lib/pact_broker/webhooks/execution.rb +25 -4
  80. data/lib/pact_broker/webhooks/job.rb +55 -13
  81. data/lib/pact_broker/webhooks/latest_triggered_webhook.rb +9 -0
  82. data/lib/pact_broker/webhooks/redact_logs.rb +10 -0
  83. data/lib/pact_broker/webhooks/repository.rb +76 -8
  84. data/lib/pact_broker/webhooks/service.rb +48 -8
  85. data/lib/pact_broker/webhooks/status.rb +29 -0
  86. data/lib/pact_broker/webhooks/triggered_webhook.rb +96 -0
  87. data/lib/pact_broker/webhooks/webhook.rb +19 -8
  88. data/lib/rack/pact_broker/database_transaction.rb +9 -3
  89. data/pact_broker.gemspec +3 -3
  90. data/public/javascripts/pact.js +5 -0
  91. data/public/stylesheets/pact.css +14 -1
  92. data/public/stylesheets/relationships.css +0 -1
  93. data/script/db-spec.sh +7 -0
  94. data/script/seed.rb +13 -8
  95. data/spec/features/create_webhook_spec.rb +1 -1
  96. data/spec/features/delete_pact_spec.rb +5 -1
  97. data/spec/features/delete_webhook_spec.rb +2 -1
  98. data/spec/features/edit_webhook_spec.rb +61 -0
  99. data/spec/features/execute_webhook_spec.rb +73 -0
  100. data/spec/features/get_latest_pact_badge_spec.rb +1 -1
  101. data/spec/features/get_latest_tagged_pact_badge_spec.rb +1 -1
  102. data/spec/features/get_latest_untagged_pact_badge_spec.rb +1 -1
  103. data/spec/features/get_pact_spec.rb +1 -1
  104. data/spec/features/merge_pact_spec.rb +1 -1
  105. data/spec/features/publish_pact_spec.rb +1 -1
  106. data/spec/integration/app_spec.rb +1 -1
  107. data/spec/integration/endpoints/group.rb +1 -1
  108. data/spec/lib/pact_broker/api/decorators/latest_pact_decorator_spec.rb +2 -1
  109. data/spec/lib/pact_broker/api/decorators/pact_decorator_spec.rb +8 -6
  110. data/spec/lib/pact_broker/api/decorators/pact_webhooks_status_decorator_spec.rb +134 -0
  111. data/spec/lib/pact_broker/api/decorators/relationships_csv_decorator_spec.rb +1 -1
  112. data/spec/lib/pact_broker/api/decorators/representable_pact_spec.rb +1 -1
  113. data/spec/lib/pact_broker/api/renderers/html_pact_renderer_spec.rb +27 -1
  114. data/spec/lib/pact_broker/api/resources/badge_spec.rb +32 -15
  115. data/spec/lib/pact_broker/api/resources/base_resource_spec.rb +17 -0
  116. data/spec/lib/pact_broker/api/resources/latest_pact_spec.rb +5 -3
  117. data/spec/lib/pact_broker/api/resources/pact_spec.rb +9 -2
  118. data/spec/lib/pact_broker/api/resources/triggered_webhook_logs_spec.rb +28 -0
  119. data/spec/lib/pact_broker/api/resources/webhook_execution_spec.rb +15 -5
  120. data/spec/lib/pact_broker/api/resources/webhook_spec.rb +43 -31
  121. data/spec/lib/pact_broker/app_spec.rb +12 -8
  122. data/spec/lib/pact_broker/badges/service_spec.rb +15 -1
  123. data/spec/lib/pact_broker/configuration_spec.rb +3 -2
  124. data/spec/lib/pact_broker/domain/relationship_spec.rb +24 -0
  125. data/spec/lib/pact_broker/domain/webhook_request_spec.rb +47 -31
  126. data/spec/lib/pact_broker/domain/webhook_spec.rb +4 -6
  127. data/spec/lib/pact_broker/pacticipants/service_spec.rb +16 -1
  128. data/spec/lib/pact_broker/pacts/repository_spec.rb +22 -1
  129. data/spec/lib/pact_broker/pacts/service_spec.rb +32 -1
  130. data/spec/lib/pact_broker/ui/view_models/relationship_spec.rb +44 -0
  131. data/spec/lib/pact_broker/verifications/repository_spec.rb +19 -0
  132. data/spec/lib/pact_broker/verifications/service_spec.rb +1 -1
  133. data/spec/lib/pact_broker/webhooks/job_spec.rb +80 -19
  134. data/spec/lib/pact_broker/webhooks/redact_logs_spec.rb +49 -0
  135. data/spec/lib/pact_broker/webhooks/repository_spec.rb +271 -21
  136. data/spec/lib/pact_broker/webhooks/service_spec.rb +70 -3
  137. data/spec/lib/pact_broker/webhooks/status_spec.rb +48 -0
  138. data/spec/lib/pact_broker/webhooks/triggered_webhook_spec.rb +40 -0
  139. data/spec/lib/rack/pact_broker/database_transaction_spec.rb +14 -4
  140. data/spec/migrations/23_pact_versions_spec.rb +8 -30
  141. data/spec/migrations/24_populate_pact_contents_spec.rb +3 -21
  142. data/spec/migrations/34_latest_tagged_pacts_spec.rb +1 -17
  143. data/spec/migrations/34_pact_revisions_spec.rb +7 -23
  144. data/spec/migrations/41_migrate_execution_data_spec.rb +109 -0
  145. data/spec/service_consumers/pact_helper.rb +5 -1
  146. data/spec/spec_helper.rb +15 -7
  147. data/spec/support/database_cleaner.rb +15 -2
  148. data/spec/support/migration_helpers.rb +16 -0
  149. data/spec/support/test_data_builder.rb +41 -9
  150. data/tasks/database.rb +7 -2
  151. data/tasks/db.rake +10 -0
  152. data/tasks/rspec.rake +1 -1
  153. data/vendor/hal-browser/browser.html +3 -2
  154. data/vendor/hal-browser/js/hal/resource.js +16 -2
  155. metadata +72 -13
  156. data/script/record_verification.sh +0 -4
@@ -3,12 +3,17 @@ require 'pact_broker/logging'
3
3
  require 'pact_broker/webhooks/job'
4
4
  require 'base64'
5
5
  require 'securerandom'
6
+ require 'pact_broker/webhooks/triggered_webhook'
7
+ require 'pact_broker/webhooks/status'
6
8
 
7
9
  module PactBroker
8
10
 
9
11
  module Webhooks
10
12
  class Service
11
13
 
14
+ PUBLICATION = PactBroker::Webhooks::TriggeredWebhook::TRIGGER_TYPE_PUBLICATION
15
+ USER = PactBroker::Webhooks::TriggeredWebhook::TRIGGER_TYPE_USER
16
+
12
17
  extend Repositories
13
18
  include Logging
14
19
 
@@ -30,25 +35,50 @@ module PactBroker
30
35
  webhook_repository.find_by_uuid uuid
31
36
  end
32
37
 
38
+ def self.update_by_uuid uuid, webhook
39
+ webhook_repository.update_by_uuid uuid, webhook
40
+ end
41
+
33
42
  def self.delete_by_uuid uuid
34
- webhook_repository.unlink_executions_by_webhook_uuid uuid
43
+ webhook_repository.unlink_triggered_webhooks_by_webhook_uuid uuid
35
44
  webhook_repository.delete_by_uuid uuid
36
45
  end
37
46
 
38
- def self.delete_by_pacticipant pacticipant
47
+ def self.delete_all_webhhook_related_objects_by_pacticipant pacticipant
48
+ webhook_repository.delete_executions_by_pacticipant pacticipant
49
+ webhook_repository.delete_triggered_webhooks_by_pacticipant pacticipant
39
50
  webhook_repository.delete_by_pacticipant pacticipant
40
51
  end
41
52
 
53
+ def self.delete_all_webhook_related_objects_by_pact_publication_ids pact_publication_ids
54
+ webhook_repository.delete_triggered_webhooks_by_pact_publication_ids pact_publication_ids
55
+ end
56
+
42
57
  def self.find_all
43
58
  webhook_repository.find_all
44
59
  end
45
60
 
46
- def self.execute_webhook_now webhook
47
- webhook_execution_result = webhook.execute
48
- webhook_repository.create_execution webhook, webhook_execution_result
61
+ def self.execute_webhook_now webhook, pact
62
+ triggered_webhook = webhook_repository.create_triggered_webhook(next_uuid, webhook, pact, USER)
63
+ webhook_execution_result = execute_triggered_webhook_now triggered_webhook, failure_log_message: "Webhook execution failed"
64
+ if webhook_execution_result.success?
65
+ webhook_repository.update_triggered_webhook_status triggered_webhook, TriggeredWebhook::STATUS_SUCCESS
66
+ else
67
+ webhook_repository.update_triggered_webhook_status triggered_webhook, TriggeredWebhook::STATUS_FAILURE
68
+ end
69
+ webhook_execution_result
70
+ end
71
+
72
+ def self.execute_triggered_webhook_now triggered_webhook, options
73
+ webhook_execution_result = triggered_webhook.execute options
74
+ webhook_repository.create_execution triggered_webhook, webhook_execution_result
49
75
  webhook_execution_result
50
76
  end
51
77
 
78
+ def self.update_triggered_webhook_status triggered_webhook, status
79
+ webhook_repository.update_triggered_webhook_status triggered_webhook, status
80
+ end
81
+
52
82
  def self.find_by_consumer_and_provider consumer, provider
53
83
  webhook_repository.find_by_consumer_and_provider consumer, provider
54
84
  end
@@ -57,22 +87,32 @@ module PactBroker
57
87
  webhooks = webhook_repository.find_by_consumer_and_provider pact.consumer, pact.provider
58
88
 
59
89
  if webhooks.any?
60
- run_later(webhooks)
90
+ run_later(webhooks, pact)
61
91
  else
62
92
  logger.debug "No webhook found for consumer \"#{pact.consumer.name}\" and provider \"#{pact.provider.name}\""
63
93
  end
64
94
  end
65
95
 
66
- def self.run_later webhooks
96
+ def self.run_later webhooks, pact
97
+ trigger_uuid = next_uuid
67
98
  webhooks.each do | webhook |
68
99
  begin
100
+ triggered_webhook = webhook_repository.create_triggered_webhook(trigger_uuid, webhook, pact, PUBLICATION)
69
101
  logger.info "Scheduling job for #{webhook.description} with uuid #{webhook.uuid}"
70
- Job.perform_async webhook: webhook
102
+ Job.perform_async triggered_webhook: triggered_webhook
71
103
  rescue StandardError => e
72
104
  log_error e
73
105
  end
74
106
  end
75
107
  end
108
+
109
+ def self.find_latest_triggered_webhooks consumer, provider
110
+ webhook_repository.find_latest_triggered_webhooks consumer, provider
111
+ end
112
+
113
+ def self.fail_retrying_triggered_webhooks
114
+ webhook_repository.fail_retrying_triggered_webhooks
115
+ end
76
116
  end
77
117
  end
78
118
  end
@@ -0,0 +1,29 @@
1
+ module PactBroker
2
+ module Webhooks
3
+ class Status
4
+
5
+ def initialize pact, webhooks, latest_triggered_webhooks
6
+ @webhooks = webhooks
7
+ @latest_triggered_webhooks = latest_triggered_webhooks
8
+ end
9
+
10
+ def to_s
11
+ to_sym.to_s
12
+ end
13
+
14
+ def to_sym
15
+ return :none if webhooks.empty?
16
+ return :not_run if latest_triggered_webhooks.empty?
17
+ if latest_triggered_webhooks.any?{|w| w.status == "retrying" }
18
+ return :retrying
19
+ end
20
+ latest_triggered_webhooks.all?{|w| w.status == "success"} ? :success : :failure
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :webhooks, :latest_triggered_webhooks
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,96 @@
1
+ require 'sequel'
2
+ require 'pact_broker/repositories/helpers'
3
+ require 'pact_broker/webhooks/execution'
4
+
5
+ module PactBroker
6
+ module Webhooks
7
+ class TriggeredWebhook < Sequel::Model(:triggered_webhooks)
8
+
9
+ TRIGGER_TYPE_PUBLICATION = 'pact_publication'
10
+ TRIGGER_TYPE_USER = 'user'
11
+
12
+ STATUS_NOT_RUN = 'not_run'.freeze
13
+ STATUS_RETRYING = 'retrying'.freeze
14
+ STATUS_SUCCESS = 'success'.freeze
15
+ STATUS_FAILURE = 'failure'.freeze
16
+
17
+ dataset_module do
18
+ include PactBroker::Repositories::Helpers
19
+
20
+ def retrying
21
+ where(status: STATUS_RETRYING)
22
+ end
23
+
24
+ def successful
25
+ where(status: STATUS_SUCCESS)
26
+ end
27
+
28
+ def failed
29
+ where(status: STATUS_FAILURE)
30
+ end
31
+
32
+ def not_run
33
+ where(status: STATUS_NOT_RUN)
34
+ end
35
+ end
36
+
37
+ associate(:one_to_many, :webhook_executions, :class => "PactBroker::Webhooks::Execution", :key => :triggered_webhook_id, :primary_key => :id, :order => :id)
38
+ associate(:many_to_one, :webhook, :class => "PactBroker::Webhooks::Webhook", :key => :webhook_id, :primary_key => :id)
39
+ associate(:many_to_one, :pact_publication, :class => "PactBroker::Pacts::PactPublication", :key => :pact_publication_id, :primary_key => :id)
40
+ associate(:many_to_one, :provider, :class => "PactBroker::Domain::Pacticipant", :key => :provider_id, :primary_key => :id)
41
+ associate(:many_to_one, :consumer, :class => "PactBroker::Domain::Pacticipant", :key => :consumer_id, :primary_key => :id)
42
+
43
+
44
+ def request_description
45
+ webhook.to_domain.request_description
46
+ end
47
+
48
+ def execute options
49
+ webhook.to_domain.execute options
50
+ end
51
+
52
+ def consumer_name
53
+ consumer && consumer.name
54
+ end
55
+
56
+ def provider_name
57
+ provider && provider.name
58
+ end
59
+
60
+ def success?
61
+ status == STATUS_SUCCESS
62
+ end
63
+
64
+ def failure?
65
+ status == STATUS_FAILURE
66
+ end
67
+
68
+ def retrying?
69
+ status == STATUS_RETRYING
70
+ end
71
+
72
+ def not_run?
73
+ status == STATUS_NOT_RUN
74
+ end
75
+
76
+ def number_of_attempts_made
77
+ webhook_executions.size
78
+ end
79
+
80
+ def finished?
81
+ success? || failure?
82
+ end
83
+
84
+ def number_of_attempts_remaining
85
+ if finished?
86
+ 0
87
+ else
88
+ (PactBroker.configuration.webhook_retry_schedule.size + 1) - number_of_attempts_made
89
+ end
90
+ end
91
+ end
92
+
93
+ TriggeredWebhook.plugin :timestamps, update_on_create: true
94
+
95
+ end
96
+ end
@@ -15,16 +15,13 @@ module PactBroker
15
15
  WebhookHeader.where(webhook_id: id).destroy
16
16
  end
17
17
 
18
+ def update_from_domain webhook
19
+ set(self.class.properties_hash_from_domain(webhook))
20
+ end
21
+
18
22
  def self.from_domain webhook, consumer, provider
19
- is_json_request_body = !(String === webhook.request.body || webhook.request.body.nil?) # Can't rely on people to set content type
20
23
  new(
21
- uuid: webhook.uuid,
22
- method: webhook.request.method,
23
- url: webhook.request.url,
24
- username: webhook.request.username,
25
- password: not_plain_text_password(webhook.request.password),
26
- body: (is_json_request_body ? webhook.request.body.to_json : webhook.request.body),
27
- is_json_request_body: is_json_request_body
24
+ properties_hash_from_domain(webhook).merge(uuid: webhook.uuid)
28
25
  ).tap do | db_webhook |
29
26
  db_webhook.consumer_id = consumer.id
30
27
  db_webhook.provider_id = provider.id
@@ -67,6 +64,20 @@ module PactBroker
67
64
  end
68
65
  end
69
66
 
67
+ private
68
+
69
+ def self.properties_hash_from_domain webhook
70
+ is_json_request_body = !(String === webhook.request.body || webhook.request.body.nil?) # Can't rely on people to set content type
71
+ {
72
+ method: webhook.request.method,
73
+ url: webhook.request.url,
74
+ username: webhook.request.username,
75
+ password: not_plain_text_password(webhook.request.password),
76
+ body: (is_json_request_body ? webhook.request.body.to_json : webhook.request.body),
77
+ is_json_request_body: is_json_request_body
78
+ }
79
+ end
80
+
70
81
  end
71
82
 
72
83
  Webhook.plugin :timestamps, :update_on_create=>true
@@ -1,4 +1,4 @@
1
- require 'pact_broker/version'
1
+ require 'pact_broker/constants'
2
2
  require 'sequel'
3
3
 
4
4
  module Rack
@@ -6,7 +6,7 @@ module Rack
6
6
  class DatabaseTransaction
7
7
 
8
8
  REQUEST_METHOD = "REQUEST_METHOD".freeze
9
- TRANS_METHODS = %{POST PUT PATCH DELETE}.freeze
9
+ TRANS_METHODS = %w{POST PUT PATCH DELETE}.freeze
10
10
 
11
11
  def initialize app, database_connection
12
12
  @app = app
@@ -33,10 +33,16 @@ module Rack
33
33
  response = nil
34
34
  @database_connection.transaction do
35
35
  response = @app.call(env)
36
- raise Sequel::Rollback if response.first == 500
36
+ if response.first == 500
37
+ raise Sequel::Rollback unless do_not_rollback?(response)
38
+ end
37
39
  end
38
40
  response
39
41
  end
42
+
43
+ def do_not_rollback? response
44
+ response[1].delete(::PactBroker::DO_NOT_ROLLBACK)
45
+ end
40
46
  end
41
47
  end
42
48
  end
data/pact_broker.gemspec CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |gem|
27
27
  gem.add_runtime_dependency 'reform', '~> 2.2'
28
28
  gem.add_runtime_dependency 'dry-validation', '~> 0.10.5'
29
29
  gem.add_runtime_dependency 'sequel', '~> 4.23'
30
- gem.add_runtime_dependency 'webmachine', '1.4.0'
30
+ gem.add_runtime_dependency 'webmachine', '1.5.0'
31
31
  gem.add_runtime_dependency 'semver2', '~> 3.4.2'
32
32
  gem.add_runtime_dependency 'rack', '~>2.0'
33
33
  gem.add_runtime_dependency 'redcarpet', '>=3.3.2', '~>3.3'
@@ -39,7 +39,7 @@ Gem::Specification.new do |gem|
39
39
  gem.add_runtime_dependency 'dry-types', '~> 0.10.3' # https://travis-ci.org/pact-foundation/pact_broker/jobs/249448621
40
40
 
41
41
  gem.add_development_dependency 'bundler-audit', '~>0.4'
42
- gem.add_development_dependency 'sqlite3'
42
+ gem.add_development_dependency 'sqlite3', '~>1.3'
43
43
  gem.add_development_dependency 'pry-byebug'
44
44
  gem.add_development_dependency 'rake', '~>10.0'
45
45
  gem.add_development_dependency 'fakefs', '~>0.4'
@@ -48,7 +48,7 @@ Gem::Specification.new do |gem|
48
48
  gem.add_development_dependency 'rspec', '~>3.0'
49
49
  gem.add_development_dependency 'rspec-its', '~>1.2'
50
50
  gem.add_development_dependency 'database_cleaner', '~>1.6'
51
- gem.add_development_dependency 'pg'
51
+ gem.add_development_dependency 'pg', '~>0.21'
52
52
  gem.add_development_dependency 'conventional-changelog', '~>1.3'
53
53
 
54
54
  end
@@ -0,0 +1,5 @@
1
+ $( document ).ready(function() {
2
+ $('.badge').click(function(){
3
+ $('.badge-markdown').toggle();
4
+ });
5
+ });
@@ -13,4 +13,17 @@ div.pact-metadata span.name {
13
13
 
14
14
  pre {
15
15
  font-size: 1em
16
- }
16
+ }
17
+
18
+ li.badge {
19
+ cursor: pointer;
20
+ }
21
+
22
+ li.badge > img {
23
+ cursor: pointer;
24
+ height: 20px;
25
+ }
26
+
27
+ div.badge-markdown {
28
+ background-color: #f8f8f8
29
+ }
@@ -48,7 +48,6 @@ body { padding-top: 10px; }
48
48
 
49
49
  .consumer, .provider {
50
50
  text-align: center;
51
- white-space: nowrap;
52
51
  }
53
52
 
54
53
  span.pact {
data/script/db-spec.sh ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/sh
2
+ set -e
3
+ cd db/test/backwards_compatibility
4
+ export BUNDLE_GEMFILE=$PWD/Gemfile
5
+ bundle install
6
+ bundle exec appraisal install
7
+ bundle exec rake
data/script/seed.rb CHANGED
@@ -10,19 +10,20 @@ require 'logger'
10
10
  DATABASE_CREDENTIALS = {logger: Logger.new($stdout), adapter: "sqlite", database: ARGV[0], :encoding => 'utf8'}
11
11
  connection = Sequel.connect(DATABASE_CREDENTIALS)
12
12
  connection.timezone = :utc
13
+ require 'pact_broker/db'
14
+ PactBroker::DB.connection = connection
13
15
  require 'pact_broker'
14
16
  require 'support/test_data_builder'
15
17
 
16
- def random_build
17
- rand * 100
18
- end
19
18
 
20
- tables_to_clean = [:labels, :webhook_executions, :verifications, :pact_publications, :pact_versions, :pacts, :pact_version_contents, :tags, :versions, :webhook_headers, :webhooks, :pacticipants]
19
+ tables_to_clean = [:labels, :webhook_executions, :triggered_webhooks, :verifications, :pact_publications, :pact_versions, :pacts, :pact_version_contents, :tags, :versions, :webhook_headers, :webhooks, :pacticipants]
21
20
 
22
21
  tables_to_clean.each do | table_name |
23
22
  connection[table_name].delete if connection.table_exists?(table_name)
24
23
  end
25
24
 
25
+
26
+
26
27
  class TestDataBuilder
27
28
  def method_missing *args
28
29
  self
@@ -52,7 +53,7 @@ TestDataBuilder.new
52
53
  .create_label("microservice")
53
54
  .create_provider("Bar")
54
55
  .create_label("microservice")
55
- .create_webhook(method: 'GET', url: 'http://127.0.0.1:1234/')
56
+ .create_webhook(method: 'GET', url: 'http://localhost:9393/')
56
57
  .create_consumer_version("1.2.100")
57
58
  .publish_pact
58
59
  .create_verification(provider_version: "1.4.234", success: true, execution_date: DateTime.now - 15)
@@ -62,7 +63,7 @@ TestDataBuilder.new
62
63
  .create_consumer_version("1.2.102")
63
64
  .publish_pact(created_at: (Date.today - 7).to_datetime)
64
65
  .create_provider("Animals")
65
- .create_webhook(method: 'GET', url: 'http://127.0.0.1:1234/')
66
+ .create_webhook(method: 'GET', url: 'http://localhost:9393/')
66
67
  .publish_pact(created_at: (Time.now - 140).to_datetime)
67
68
  .create_verification(provider_version: "2.0.366", execution_date: Date.today - 2) #changed
68
69
  .create_provider("Wiffles")
@@ -73,12 +74,16 @@ TestDataBuilder.new
73
74
  .publish_pact(created_at: (Date.today - 1).to_datetime)
74
75
  .create_consumer("The Android App")
75
76
  .create_provider("The back end")
76
- .create_webhook(method: 'GET', url: 'http://127.0.0.1:1234/')
77
+ .create_webhook(method: 'GET', url: 'http://localhost:9393/')
77
78
  .create_consumer_version("1.2.106")
78
79
  .publish_pact
79
80
  .create_consumer("Some other app")
80
81
  .create_provider("A service")
81
- .create_webhook(method: 'GET', url: 'http://127.0.0.1:1234/')
82
+ .create_webhook(method: 'GET', url: 'http://localhost:9393/')
83
+ .create_triggered_webhook(status: 'success')
84
+ .create_webhook_execution
85
+ .create_webhook(method: 'POST', url: 'http://foo:9393/')
86
+ .create_triggered_webhook(status: 'failure')
82
87
  .create_webhook_execution
83
88
  .create_consumer_version("1.2.106")
84
89
  .publish_pact(created_at: (Date.today - 26).to_datetime)
@@ -3,7 +3,7 @@ require 'support/test_data_builder'
3
3
  describe "Creating a webhook" do
4
4
 
5
5
  before do
6
- TestDataBuilder.new.create_pact_with_hierarchy("Some Consumer", "1", "Some Provider")
6
+ TestDataBuilder.new.create_pact_with_hierarchy("Some Consumer", "1", "Some Provider").and_return(:pact)
7
7
  end
8
8
 
9
9
  let(:path) { "/webhooks/provider/Some%20Provider/consumer/Some%20Consumer" }
@@ -8,7 +8,11 @@ describe "Deleting a pact" do
8
8
 
9
9
  context "when the pact exists" do
10
10
  before do
11
- TestDataBuilder.new.create_pact_with_hierarchy "A Consumer", "1.2.3", "A Provider"
11
+ TestDataBuilder.new
12
+ .create_pact_with_hierarchy("A Consumer", "1.2.3", "A Provider")
13
+ .create_webhook
14
+ .create_triggered_webhook
15
+ .create_deprecated_webhook_execution
12
16
  end
13
17
 
14
18
  it "deletes the pact" do
@@ -9,7 +9,8 @@ describe "Delete a webhook" do
9
9
  .create_provider
10
10
  .create_pact
11
11
  .create_webhook
12
- .create_webhook_execution
12
+ .create_triggered_webhook
13
+ .create_deprecated_webhook_execution
13
14
  .and_return(:webhook)
14
15
  end
15
16
 
@@ -0,0 +1,61 @@
1
+ require 'support/test_data_builder'
2
+
3
+ describe "Creating a webhook" do
4
+
5
+ let(:td) { TestDataBuilder.new }
6
+
7
+ before do
8
+ td.create_pact_with_hierarchy("Some Consumer", "1", "Some Provider")
9
+ .create_webhook
10
+ end
11
+
12
+ let(:path) { "/webhooks/#{td.webhook.uuid}" }
13
+ let(:headers) { {'CONTENT_TYPE' => 'application/json'} }
14
+ let(:response_body) { JSON.parse(last_response.body, symbolize_names: true)}
15
+ let(:webhook_json) do
16
+ h = load_json_fixture('webhook_valid.json')
17
+ h['request']['method'] = 'GET'
18
+ h.to_json
19
+ end
20
+
21
+ let(:reloaded_webhook) { PactBroker::Webhooks::Repository.new.find_by_uuid(td.webhook.uuid) }
22
+
23
+ subject { put path, webhook_json, headers; last_response }
24
+
25
+ context "with invalid attributes" do
26
+ let(:webhook_json) { '{}' }
27
+
28
+ it "returns a 400" do
29
+ subject
30
+ expect(last_response.status).to be 400
31
+ end
32
+
33
+ it "returns the validation errors" do
34
+ subject
35
+ expect(response_body[:errors]).to_not be_empty
36
+ end
37
+
38
+ it "does not update the webhook" do
39
+ expect(reloaded_webhook.request.method).to eq 'POST'
40
+ end
41
+ end
42
+
43
+ context "with valid attributes" do
44
+ let(:webhook_hash) { JSON.parse(webhook_json, symbolize_names: true) }
45
+
46
+ it "returns a 200 response" do
47
+ subject
48
+ expect(last_response.status).to be 200
49
+ end
50
+
51
+ it "returns a JSON Content Type" do
52
+ subject
53
+ expect(last_response.headers['Content-Type']).to eq 'application/hal+json;charset=utf-8'
54
+ end
55
+
56
+ it "updates the webhook" do
57
+ subject
58
+ expect(reloaded_webhook.request.method).to eq 'GET'
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,73 @@
1
+ require 'support/test_data_builder'
2
+ require 'webmock/rspec'
3
+ require 'rack/pact_broker/database_transaction'
4
+
5
+ describe "Execute a webhook" do
6
+
7
+ let(:td) { TestDataBuilder.new }
8
+
9
+ before do
10
+ td.create_pact_with_hierarchy("Some Consumer", "1", "Some Provider")
11
+ .create_webhook(method: 'POST')
12
+ end
13
+
14
+ let(:path) { "/webhooks/#{td.webhook.uuid}/execute" }
15
+ let(:response_body) { JSON.parse(last_response.body, symbolize_names: true)}
16
+
17
+ subject { post path; last_response }
18
+
19
+ context "when the execution is successful" do
20
+ let!(:request) do
21
+ stub_request(:post, /http/).to_return(:status => 200)
22
+ end
23
+
24
+ it "performs the HTTP request" do
25
+ subject
26
+ expect(request).to have_been_made
27
+ end
28
+
29
+ it "returns a 200 response" do
30
+ expect(subject.status).to be 200
31
+ end
32
+
33
+ it "saves a TriggeredWebhook" do
34
+ expect { subject }.to change { PactBroker::Webhooks::TriggeredWebhook.count }.by(1)
35
+ end
36
+
37
+ it "saves a WebhookExecution" do
38
+ expect { subject }.to change { PactBroker::Webhooks::Execution.count }.by(1)
39
+ end
40
+ end
41
+
42
+ context "when an error occurs", no_db_clean: true do
43
+ let(:app) { Rack::PactBroker::DatabaseTransaction.new(PactBroker::API, PactBroker::DB.connection) }
44
+
45
+ let!(:request) do
46
+ stub_request(:post, /http/).to_raise(Errno::ECONNREFUSED)
47
+ end
48
+
49
+ before do
50
+ PactBroker::Database.truncate
51
+ td.create_pact_with_hierarchy("Some Consumer", "1", "Some Provider")
52
+ .create_webhook(method: 'POST')
53
+ end
54
+
55
+ after do
56
+ PactBroker::Database.truncate
57
+ end
58
+
59
+ subject { post path; last_response }
60
+
61
+ it "returns a 500 response" do
62
+ expect(subject.status).to be 500
63
+ end
64
+
65
+ it "saves a TriggeredWebhook" do
66
+ expect { subject }.to change { PactBroker::Webhooks::TriggeredWebhook.count }.by(1)
67
+ end
68
+
69
+ it "saves a WebhookExecution" do
70
+ expect { subject }.to change { PactBroker::Webhooks::Execution.count }.by(1)
71
+ end
72
+ end
73
+ end
@@ -3,7 +3,7 @@ require 'webmock/rspec'
3
3
  describe "get latest pact badge" do
4
4
 
5
5
  before do
6
- PactBroker.configuration.enable_badge_resources = true
6
+ PactBroker.configuration.enable_public_badge_access = true
7
7
  TestDataBuilder.new
8
8
  .create_consumer('consumer')
9
9
  .create_provider('provider')
@@ -3,7 +3,7 @@ require 'webmock/rspec'
3
3
  describe "get latest tagged pact badge" do
4
4
 
5
5
  before do
6
- PactBroker.configuration.enable_badge_resources = true
6
+ PactBroker.configuration.enable_public_badge_access = true
7
7
  PactBroker.configuration.shields_io_base_url = nil
8
8
  TestDataBuilder.new
9
9
  .create_consumer('consumer')
@@ -3,7 +3,7 @@ require 'webmock/rspec'
3
3
  describe "get latest untagged pact badge" do
4
4
 
5
5
  before do
6
- PactBroker.configuration.enable_badge_resources = true
6
+ PactBroker.configuration.enable_public_badge_access = true
7
7
  PactBroker.configuration.shields_io_base_url = nil
8
8
  TestDataBuilder.new
9
9
  .create_consumer('consumer')
@@ -7,7 +7,7 @@ describe "retrieving a pact" do
7
7
  let(:path) { "/pacts/provider/a%20provider/consumer/a%20consumer/version/1.2.3A" }
8
8
 
9
9
  before do
10
- TestDataBuilder.new.create_pact_with_hierarchy "A Consumer", "1.2.3a", "A Provider"
10
+ TestDataBuilder.new.create_pact_with_hierarchy("A Consumer", "1.2.3a", "A Provider").and_return(:pact)
11
11
  end
12
12
 
13
13
  context "when case sensitivity is turned on" do
@@ -29,7 +29,7 @@ describe "Merging a pact" do
29
29
  let(:merged_pact_content) { load_fixture('a_consumer-a_provider-merged.json') }
30
30
 
31
31
  before do
32
- TestDataBuilder.new.create_pact_with_hierarchy "A Consumer", "1.2.3", "A Provider", existing_pact_content
32
+ TestDataBuilder.new.create_pact_with_hierarchy("A Consumer", "1.2.3", "A Provider", existing_pact_content).and_return(:pact)
33
33
  end
34
34
 
35
35
  it "returns a 200 Success" do
@@ -23,7 +23,7 @@ describe "Publishing a pact" do
23
23
  context "when a pact for this consumer version does exist" do
24
24
 
25
25
  before do
26
- TestDataBuilder.new.create_pact_with_hierarchy "A Consumer", "1.2.3", "A Provider"
26
+ TestDataBuilder.new.create_pact_with_hierarchy("A Consumer", "1.2.3", "A Provider").and_return(:pact)
27
27
  end
28
28
 
29
29
  it "returns a 200 Success" do