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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7902c1cd120ea0eba915a6c88bfa1e63b922f5a1
4
- data.tar.gz: 01d8538b925d01e927a08de783421316ad3c57d0
3
+ metadata.gz: e6bcfaf002c3150d58c06e7790c4eeffcd875870
4
+ data.tar.gz: 4529da832fd2ea9078adbd73043720f68a50f8cb
5
5
  SHA512:
6
- metadata.gz: 549cfab358749c88bc019b180dc7030e001d27c33657c44d8104e72f66881b20c9ece90c8dadd7bcf80a8441421afc5287722b65e415c0104405c95bfca28efb
7
- data.tar.gz: b29f53fb8f58273b45270d45d6b46b1124233fa3474016bbcf616b1acb020a0d2898f0c84e3f929ae9de5ccc6bb85ff96bf2402fe0c86e06a40579b75e38492b
6
+ metadata.gz: 2088e2c7318966335c99761ebefdac09df3af9afec1fcc461fee3fbb2d20ba362b83aa1f99c3067dfbd56f30532dc0176fcd9d298c5d8c3ac0a99a166cb4d64e
7
+ data.tar.gz: a6f0fe6b337d2cf5af0ab444c71962b6a9ebad1a1a11bc251d212fe89593f0fa1d75a5b6df1adac1a561e4d29cab443608e857796c2c68aefbf2da743f4778b4
data/.gitignore CHANGED
@@ -30,3 +30,6 @@ Gemfile.lock
30
30
  bethtest/
31
31
  bin/
32
32
  coverage
33
+ db/test/backwards_compatibility/pids
34
+ db/test/backwards_compatibility/pact_broker_database.sqlite3
35
+ spec/examples.txt
data/.travis.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- # - 2.2.7
4
- # - 2.3.4
5
3
  - 2.4.1
4
+ - 2.3.4
5
+ - 2.2.7
6
6
  services:
7
7
  - postgresql
8
8
  - mysql
@@ -20,9 +20,11 @@ before_script:
20
20
  - cp config/database.travis.yml config/database.yml
21
21
  - psql -U postgres -c "CREATE DATABASE pact_broker;"
22
22
  - mysql -e 'CREATE DATABASE pact_broker;'
23
+ - mysql -e "GRANT ALL ON pact_broker.* TO 'travis'@'%';"
23
24
  - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
24
25
  - chmod +x ./cc-test-reporter
25
26
  script:
26
27
  - bundle exec rake
27
28
  - if [ "$DATABASE_ADAPTER" == "postgres" ]; then ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT || true; fi
29
+ - if [ ! -z "$(ruby --version | grep '2\.4\.')" ]; then ./script/db-spec.sh; fi
28
30
  - bundle exec bundle-audit update && bundle exec bundle-audit
data/CHANGELOG.md CHANGED
@@ -1,3 +1,57 @@
1
+ <a name="v2.5.0"></a>
2
+ ### v2.5.0 (2017-09-25)
3
+
4
+ #### Features
5
+
6
+ * **heartbeat resource**
7
+ * cache json response body ([f2ac0f5](/../../commit/f2ac0f5))
8
+
9
+ * **webhook status**
10
+ * delete webhook objects related to previous revisions of a pact when deleting a pact publication ([a053623](/../../commit/a053623))
11
+ * delete related triggered webhooks and executions when pact publication is deleted ([3dc590c](/../../commit/3dc590c))
12
+ * set any triggered webhooks in 'retrying' status to 'failed' on startup ([1f2305b](/../../commit/1f2305b))
13
+ * migrate webhook execution data to triggered webhooks ([9f46d86](/../../commit/9f46d86))
14
+ * consider http status < 300 to be a webhook failure ([7ef595a](/../../commit/7ef595a))
15
+ * log unhandled suckerpunch errors ([4cc779d](/../../commit/4cc779d))
16
+ * log number of seconds until next webhook attempt in webhook logs ([5d16330](/../../commit/5d16330))
17
+ * display attempts made and attempts remaining in webhook status resource ([648e1c3](/../../commit/648e1c3))
18
+ * move webhook retry schedule to configuration ([f2d92f3](/../../commit/f2d92f3))
19
+ * ensure triggered webhook and webhook execution objects are saved to database even when webhook fails and response code is 500 ([88ba2ac](/../../commit/88ba2ac))
20
+ * redact authorization headers in webhook logs ([10efddb](/../../commit/10efddb))
21
+ * implement PUT for webhook resource ([7266b1e](/../../commit/7266b1e))
22
+ * add endpoint for triggered webhook execution logs ([ad81d20](/../../commit/ad81d20))
23
+
24
+ * **hal browser**
25
+ * use name over title in embedded resource heading ([6c61da7](/../../commit/6c61da7))
26
+ * improve readability of link collections ([0a9bc8c](/../../commit/0a9bc8c))
27
+ * use name and title from self link when not specified in embedded resource ([354374c](/../../commit/354374c))
28
+
29
+ * **versions resource**
30
+ * deprecate versions and pacticipant links in favour of pb:versions and pb:pacticipants ([94f395e](/../../commit/94f395e))
31
+
32
+ * **badges**
33
+ * only cache successful badge responses from shields.io ([e5f08ad](/../../commit/e5f08ad))
34
+ * use simple in-memory cache for badges ([2453c55](/../../commit/2453c55))
35
+ * show message about enabling public badge access when disabled ([6fc78ff](/../../commit/6fc78ff))
36
+ * show badge in HTML pact and display markdown when clicked ([e9b632a](/../../commit/e9b632a))
37
+ * changed configuration property name from 'enable_badge_resources' to 'enable_public_badge_access' ([83540e5](/../../commit/83540e5))
38
+
39
+ * **resources**
40
+ * improve usage of title and name attributes ([915a7ee](/../../commit/915a7ee))
41
+
42
+ * **pact resource**
43
+ * improve usage of name and title fields ([3a9a178](/../../commit/3a9a178))
44
+ * add link relation for all pact versions ([d5ea068](/../../commit/d5ea068))
45
+
46
+ * **gems**
47
+ * upgrade webmachine to 1.5.0 ([d23fedc](/../../commit/d23fedc))
48
+
49
+ #### Bug Fixes
50
+
51
+ * return correct "latest" verification when a verification has been published for a pact with a revision ([f2b4c9f](/../../commit/f2b4c9f))
52
+ * sequel migration 25 for mysql ([920c363](/../../commit/920c363))
53
+ * sequel migration 19 for mysql ([0ee48e1](/../../commit/0ee48e1))
54
+
1
55
  <a name="v2.4.2"></a>
2
56
  ### v2.4.2 (2017-09-07)
3
57
 
@@ -2,10 +2,14 @@
2
2
 
3
3
  ## Domain and database design
4
4
 
5
+ ### Domain
6
+
7
+ Domain classes are found in `lib/pact_broker/domain`. Many of these classes are Sequel models, as the difference between the Sequel model and the functionality required for the domain logic is similar enough to share the class. Some classes separate the domain and database logic, as the concerns are too different. Where there is a separate database model, this will be kept in a module with the pluralized name of the model eg. `PactBroker::Webhooks`. Unfortunately, this sometimes makes it difficult to tell in the calling code whether you have a domain or a database model. I haven't worked out a clean way to handle this yet.
8
+
5
9
  ### Tables
6
- * `pact_version_contents` - the JSON content of each UNIQUE pact document is stored in this table. The same content is likely to be published over and over again by the CI builds, so deduplicating the content saves us a lot of disk space. Once created, a row is never modified.
10
+ * `pact_versions` - the JSON content of each UNIQUE pact document is stored in this table. The same content is likely to be published over and over again by the CI builds, so deduplicating the content saves us a lot of disk space. Once created, a row is never modified. Uniqueness is just done on string equality - no special pact logic. This means that pacts with randomly generated values or orders (most of pact-jvm pacts!) will get a new version record every time they publish.
7
11
 
8
- * `pact_revisions` - this table holds references to the:
12
+ * `pact_publications` - this table holds references to the:
9
13
 
10
14
  * `provider` (in the pacticipants table)
11
15
  * `consumer version` (in the versions table),
@@ -35,19 +39,19 @@
35
39
 
36
40
  ### Views
37
41
 
38
- * `all_pact_revisions` - A denormalised view the one-to-one attributes of a `pact_revision`, including:
42
+ * `all_pact_publications` - A denormalised view the one-to-one attributes of a `pact_publication`, including:
39
43
 
40
44
  * `provider name` and `provider id`
41
45
  * `consumer name` and `consumer id`
42
46
  * `consumer version number` and `consumer version order`
43
47
  * `revision_number`
44
48
 
45
- * `all_pacts` - This view has the same columns as `all_pact_revisions`, but it only contains the latest (current) revision of the pact for each provider/consumer/version. It maps to what a user would consider the "pact" resource ie. `/pacts/provider/Provider/consumer/Consumer/version/1.2.3`
49
+ * `latest_pact_publications` - This view has the same columns as `all_pact_publications`, but it only contains the latest revision of the pact for each provider/consumer/version. It maps to what a user would consider the "pact" resource ie. `/pacts/provider/Provider/consumer/Consumer/version/1.2.3`. Previous revisions are not currently exposed via the API.
46
50
 
47
- The AllPacts Sequel model in the code is what is used when querying data for displaying in a response, rather than the normalised separate PactRevision and PactVersionContent models.
51
+ The `AllPactPublications` Sequel model in the code is what is used when querying data for displaying in a response, rather than the normalised separate PactPublication and PactVersion models.
48
52
 
49
- * `latest_pacts` - This view has the same columns as `all_pact_revisions`, but it only contains the latest revision of the pact for the latest consumer version for each consumer/provider pair. It is what a user would consider the "latest pact", and maps to the resource at `/pacts/provider/Provider/consumer/Consumer/latest`
53
+ * `latest_pact_publications` - This view has the same columns as `all_pact_publications`, but it only contains the latest revision of the pact for the latest consumer version for each consumer/provider pair. It is what a user would consider the "latest pact", and maps to the resource at `/pacts/provider/Provider/consumer/Consumer/latest`
50
54
 
51
- * `latest_tagged_pacts` - This view has the same columns as `all_pact_revisions`, plus a `tag_name` column. It is used to return the pact for the latest tagged version of a consumer.
55
+ * `latest_tagged_pact_publications` - This view has the same columns as `all_pact_publications`, plus a `tag_name` column. It is used to return the pact for the latest tagged version of a consumer.
52
56
 
53
57
  * `latest_verifications` - The most recent verification for each pact version.
data/README.md CHANGED
@@ -26,7 +26,7 @@ Features:
26
26
  * Provides badges to display pact verification statuses in your READMEs.
27
27
  * Enables a pact version to be tagged (ie. "prod") so a provider can verify itself against a fixed version of a pact to ensure backwards compatibility.
28
28
  * Provides webhooks to trigger a provider build when a consumer publishes a change to a pact.
29
- * Tracks changes between Pact versions so you can tell when a consumer has changed its expectations.
29
+ * View diffs between Pact versions so you can tell what expectations have changed.
30
30
  * [Docker Pact Broker][docker]
31
31
 
32
32
  ### How would I use the Pact Broker?
@@ -125,6 +125,10 @@ You can use the [Pact Broker Docker container][docker] or [Terraform on AWS][ter
125
125
  * For production usage, use a web application server like [Phusion Passenger](https://www.phusionpassenger.com) or [Nginx](http://nginx.org/) to serve the Pact Broker application.
126
126
  * Deploy to your location of choice.
127
127
 
128
+ ## Upgrading
129
+
130
+ Please read the [UPGRADING.md](UPGRADING.md) documentation before upgrading your Pact Broker, for information on the supported upgrade paths.
131
+
128
132
  [decouple]: http://techblog.realestate.com.au/enter-the-pact-matrix-or-how-to-decouple-the-release-cycles-of-your-microservices/
129
133
  [pact]: https://github.com/realestate-com-au/pact
130
134
  [nerf]: https://github.com/pact-foundation/pact_broker/wiki/pact-broker-ci-nerf-gun
data/UPGRADING.md ADDED
@@ -0,0 +1,18 @@
1
+ # Upgrading from a previous version of the Pact Broker
2
+
3
+ ## Pact Broker versions >= 2.1.0
4
+
5
+ Backwards compatibility tests will ensure that the latest version of the database will be compatible with a previous version of the code until v3.0.0 for the following endpoints:
6
+
7
+ * Tag version
8
+ * Publish pact
9
+ * Retrieve latest pact
10
+ * Retrieve latest pact for tag
11
+
12
+ This means that zero downtime rolling upgrades for architectures that use multiple web servers (eg. Amazon autoscaling groups) are supported between any two versions from 2.1.0.
13
+
14
+ When backwards-incompatible changes need to be made in the future, a zero downtime upgrade path will documented on this page.
15
+
16
+ ## Pact Broker < 2.1.0
17
+
18
+ The upgrades between 1.18.0 and 2.1.0 contains database migrations that are NOT backwards compatible with previous versions of the code. It is recommended to run a single instance of the broker while performing an upgrade that traverses these versions.
@@ -2,9 +2,17 @@ require 'digest/sha1'
2
2
  require_relative 'migration_helper'
3
3
 
4
4
  Sequel.migration do
5
- change do
5
+ up do
6
+ PactBroker::MigrationHelper.with_mysql do
7
+ run("SET FOREIGN_KEY_CHECKS = 0")
8
+ end
9
+
6
10
  alter_table(:pacts) do
7
11
  set_column_not_null(:pact_version_content_sha)
8
12
  end
13
+
14
+ PactBroker::MigrationHelper.with_mysql do
15
+ run("SET FOREIGN_KEY_CHECKS = 1")
16
+ end
9
17
  end
10
18
  end
@@ -1,8 +1,16 @@
1
1
  Sequel.migration do
2
2
  up do
3
+ PactBroker::MigrationHelper.with_mysql do
4
+ run("SET FOREIGN_KEY_CHECKS = 0")
5
+ end
6
+
3
7
  alter_table(:pact_versions) do
4
8
  set_column_not_null(:consumer_id)
5
9
  set_column_not_null(:provider_id)
6
10
  end
11
+
12
+ PactBroker::MigrationHelper.with_mysql do
13
+ run("SET FOREIGN_KEY_CHECKS = 1")
14
+ end
7
15
  end
8
16
  end
@@ -0,0 +1,19 @@
1
+ Sequel.migration do
2
+ change do
3
+ create_table(:triggered_webhooks, charset: 'utf8') do
4
+ primary_key :id
5
+ String :trigger_uuid, null: false
6
+ String :trigger_type, null: false # publication or manual
7
+ foreign_key :pact_publication_id, :pact_publications, null: false
8
+ foreign_key :webhook_id, :webhooks
9
+ String :webhook_uuid, null: false # keep so we can group executions even when webhook is deleted
10
+ foreign_key :consumer_id, :pacticipants, null: false
11
+ foreign_key :provider_id, :pacticipants, null: false
12
+ String :status, null: false
13
+ DateTime :created_at, null: false
14
+ DateTime :updated_at, null: false
15
+ index [:webhook_id, :trigger_uuid], unique: true, name: 'uq_triggered_webhook_wi'
16
+ index [:pact_publication_id, :webhook_id, :trigger_uuid], unique: true, name: 'uq_triggered_webhook_ppi_wi'
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ Sequel.migration do
2
+ change do
3
+ alter_table(:webhook_executions) do
4
+ add_foreign_key :triggered_webhook_id, :triggered_webhooks
5
+ set_column_allow_null(:webhook_id)
6
+ set_column_allow_null(:pact_publication_id)
7
+ set_column_allow_null(:consumer_id)
8
+ set_column_allow_null(:provider_id)
9
+ end
10
+
11
+ # Hope old code doesn't insert another webhook in the meantime!
12
+
13
+ # TODO drop_column(:webhook_executions, :webhook_id)
14
+ # TODO drop_column(:webhook_executions, :webhook_uuid)
15
+ # TODO drop_column(:webhook_executions, :pact_publication_id)
16
+ # TODO drop_column(:webhook_executions, :consumer_id)
17
+ # TODO drop_column(:webhook_executions, :provider_id)
18
+
19
+ # TODO
20
+ # alter_table(:triggered_webhooks) do
21
+ # set_column_not_null(:triggered_webhook_id)
22
+ # end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ Sequel.migration do
2
+ up do
3
+ create_or_replace_view(:latest_triggered_webhook_ids,
4
+ "select webhook_uuid, consumer_id, provider_id, max(created_at) as latest_triggered_webhook_created_at
5
+ from triggered_webhooks
6
+ group by webhook_uuid, consumer_id, provider_id"
7
+ )
8
+
9
+ create_view(:latest_triggered_webhooks,
10
+ "select tw.*
11
+ from triggered_webhooks tw
12
+ inner join latest_triggered_webhook_ids ltwi
13
+ on tw.consumer_id = ltwi.consumer_id
14
+ and tw.provider_id = ltwi.provider_id
15
+ and tw.webhook_uuid = ltwi.webhook_uuid
16
+ and tw.created_at = ltwi.latest_triggered_webhook_created_at"
17
+ )
18
+ end
19
+
20
+ down do
21
+ drop_view(:latest_triggered_webhooks)
22
+ drop_view(:latest_triggered_webhook_ids)
23
+ end
24
+ end
@@ -0,0 +1,47 @@
1
+ require 'securerandom'
2
+
3
+ Sequel.migration do
4
+ up do
5
+ from(:webhook_executions).each do | execution |
6
+ pact_publication = from(:all_pact_publications).where(
7
+ consumer_id: execution[:consumer_id],
8
+ provider_id: execution[:provider_id]
9
+ ).where(
10
+ Sequel.lit("created_at <= ?", execution[:created_at])
11
+ ).reverse_order(:id).limit(1).single_record
12
+
13
+ if pact_publication && execution[:webhook_id]
14
+ webhook = from(:webhooks).where(id: execution[:webhook_id]).single_record
15
+
16
+ if webhook
17
+ webhook_uuid = webhook[:uuid]
18
+ status = execution[:success] ? 'success' : 'failure'
19
+
20
+ from(:triggered_webhooks).insert(
21
+ trigger_uuid: SecureRandom.urlsafe_base64,
22
+ trigger_type: 'pact_publication',
23
+ pact_publication_id: pact_publication[:id],
24
+ webhook_id: execution[:webhook_id],
25
+ webhook_uuid: webhook_uuid,
26
+ consumer_id: execution[:consumer_id],
27
+ provider_id: execution[:provider_id],
28
+ created_at: execution[:created_at],
29
+ updated_at: execution[:created_at],
30
+ status: status
31
+ )
32
+ end
33
+ end
34
+ from(:webhook_executions)
35
+ .where(id: execution[:id])
36
+ .update(
37
+ webhook_id: nil,
38
+ consumer_id: nil,
39
+ provider_id: nil,
40
+ pact_publication_id: nil)
41
+ end
42
+ end
43
+
44
+ down do
45
+ from(:triggered_webhooks).delete
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format documentation
3
+ --require spec_helper
@@ -0,0 +1,49 @@
1
+ # appraise "1.1.0" do
2
+ # gem "pact_broker", "1.1.0"
3
+ # gem "roar", "~>0.1"
4
+ # gem "sequel", "4.13.0"
5
+ # gem "webmachine", "1.2.2"
6
+ # end
7
+
8
+ # appraise "1.2.0" do
9
+ # gem "pact_broker", "1.2.0"
10
+ # gem "sequel", "4.13.0"
11
+ # gem "webmachine", "1.2.2"
12
+ # end
13
+
14
+ appraise "1.18.0" do
15
+ gem "pact_broker", "1.18.0"
16
+ gem "dry-types", "0.10"
17
+ end
18
+
19
+ appraise "2.0.0" do
20
+ gem "pact_broker", "2.0.0"
21
+ gem "dry-types", "0.10"
22
+ end
23
+
24
+ appraise "2.0.0" do
25
+ gem "pact_broker", "2.0.0"
26
+ gem "dry-types", "0.10"
27
+ end
28
+
29
+ appraise "2.1.0" do
30
+ gem "pact_broker", "2.1.0"
31
+ gem "dry-types", "0.10"
32
+ end
33
+
34
+ appraise "2.2.0" do
35
+ gem "pact_broker", "2.2.0"
36
+ gem "dry-types", "0.10.3"
37
+ end
38
+
39
+ appraise "2.3.0" do
40
+ gem "pact_broker", "2.3.0"
41
+ end
42
+
43
+ appraise "2.4.2" do
44
+ gem "pact_broker", "2.4.2"
45
+ end
46
+
47
+ appraise "head" do
48
+ gem "pact_broker", path: "../../../"
49
+ end
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'pact_broker'
4
+ gem 'sqlite3', '~>1.3'
5
+ gem 'pg', '~>0.21'
6
+ gem 'mysql2', '~>0.3.15'
7
+ gem 'thin', '~>1.3'
8
+ gem 'appraisal'
9
+ gem 'rspec'
10
+ gem 'rake', '~>12.0'
11
+ gem 'rack-reverse-proxy', '~>0.12'
@@ -0,0 +1,55 @@
1
+ require 'rspec/core'
2
+ require 'rspec/core/rake_task'
3
+
4
+ TESTS = [
5
+ %w{head 9297},
6
+ %w{2.4.2 9296},
7
+ %w{2.3.0 9295},
8
+ %w{2.2.0 9294},
9
+ %w{2.1.0 9293}
10
+ ]
11
+
12
+ DATABASE_VERSION = TESTS.first.first
13
+
14
+ def start_pact_broker code_version, port
15
+ Bundler.with_clean_env do
16
+ IO.popen("bundle exec appraisal #{code_version} rackup -p #{port}")
17
+ end
18
+ end
19
+
20
+ def kill_servers
21
+ Dir.chdir('pids') { Dir.glob("*") }.collect(&:to_i).each do | pid |
22
+ Process.kill 'KILL', pid
23
+ end
24
+ end
25
+
26
+ def clean
27
+ require 'fileutils'
28
+ FileUtils.rm_rf 'pids'
29
+ FileUtils.mkdir 'pids'
30
+ FileUtils.rm_rf 'pact_broker_database.sqlite3'
31
+ FileUtils.rm_rf 'log'
32
+ end
33
+
34
+ RSpec::Core::RakeTask.new(:spec) do |task|
35
+ task.pattern = 'spec/**/*_spec.rb'
36
+ end
37
+
38
+ desc 'Ensure code from previous versions is compatible with latest database'
39
+ task 'db:check_backwards_compatibility' do
40
+ ENV['PACT_BROKER_DATABASE_VERSION'] = DATABASE_VERSION
41
+ clean
42
+ begin
43
+ TESTS.each do | (code_version, port) |
44
+ start_pact_broker code_version, port
45
+
46
+ ENV['PACT_BROKER_CODE_VERSION'] = code_version
47
+ ENV['PORT'] = port
48
+ Rake::Task["spec"].execute
49
+ end
50
+ ensure
51
+ kill_servers
52
+ end
53
+ end
54
+
55
+ task :default => ['db:check_backwards_compatibility']
@@ -0,0 +1,18 @@
1
+ require 'fileutils'
2
+ require 'logger'
3
+ require 'sequel'
4
+ require 'pact_broker'
5
+
6
+ FileUtils.mkdir_p "pids"
7
+ FileUtils.touch "pids/#{Process.pid}"
8
+
9
+ DATABASE_CREDENTIALS = {adapter: "sqlite", database: "pact_broker_database.sqlite3", :encoding => 'utf8'}
10
+
11
+ app = PactBroker::App.new do | config |
12
+ config.database_connection = Sequel.connect(DATABASE_CREDENTIALS.merge(:logger => config.logger))
13
+ config.auto_migrate_db = true
14
+ end
15
+
16
+ PactBroker.logger.info "Running PactBroker #{PactBroker::VERSION}"
17
+
18
+ run app
@@ -0,0 +1,14 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "pact_broker", "1.18.0"
6
+ gem "sqlite3", "~>1.3"
7
+ gem "pg", "~>0.21"
8
+ gem "mysql2", "~>0.3.15"
9
+ gem "thin", "~>1.3"
10
+ gem "appraisal"
11
+ gem "rspec"
12
+ gem "rake", "~>12.0"
13
+ gem "rack-reverse-proxy", "~>0.12"
14
+ gem "dry-types", "0.10"