pact_broker 2.71.0 → 2.72.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +1 -21
  3. data/CHANGELOG.md +11 -0
  4. data/Dockerfile +5 -1
  5. data/docker-compose-ci-mysql.yml +37 -0
  6. data/lib/pact_broker/api/pact_broker_urls.rb +5 -1
  7. data/lib/pact_broker/api/resources/metadata_resource_methods.rb +23 -0
  8. data/lib/pact_broker/api/resources/pact.rb +2 -13
  9. data/lib/pact_broker/api/resources/pact_resource_methods.rb +23 -0
  10. data/lib/pact_broker/api/resources/pact_version.rb +3 -0
  11. data/lib/pact_broker/api/resources/tagged_pact_versions.rb +4 -0
  12. data/lib/pact_broker/api/resources/verifications.rb +2 -4
  13. data/lib/pact_broker/db/clean_incremental.rb +132 -22
  14. data/lib/pact_broker/db/delete_overwritten_data.rb +55 -27
  15. data/lib/pact_broker/domain/tag.rb +42 -0
  16. data/lib/pact_broker/domain/verification.rb +87 -0
  17. data/lib/pact_broker/metrics/service.rb +5 -3
  18. data/lib/pact_broker/pacts/all_pact_publications.rb +8 -0
  19. data/lib/pact_broker/pacts/repository.rb +35 -11
  20. data/lib/pact_broker/tasks/clean_task.rb +9 -3
  21. data/lib/pact_broker/tasks/delete_overwritten_data_task.rb +23 -7
  22. data/lib/pact_broker/test/test_data_builder.rb +24 -0
  23. data/lib/pact_broker/version.rb +1 -1
  24. data/script/docker-container/test.sh +3 -0
  25. data/script/docker/db-psql.sh +3 -0
  26. data/script/docker/db-reload.sh +11 -0
  27. data/script/pry.rb +25 -0
  28. data/script/seed.rb +1 -0
  29. data/script/test/run-rake-on-docker-compose-mysql.sh +8 -0
  30. data/spec/features/delete_tagged_pact_versions_spec.rb +2 -2
  31. data/spec/features/get_pact_spec.rb +2 -2
  32. data/spec/features/get_pact_version.rb +26 -3
  33. data/spec/fixtures/approvals/clean_incremental_dry_run.approved.json +100 -0
  34. data/spec/lib/pact_broker/api/pact_broker_urls_spec.rb +6 -0
  35. data/spec/lib/pact_broker/api/resources/pact_spec.rb +20 -9
  36. data/spec/lib/pact_broker/api/resources/tagged_pact_versions_spec.rb +10 -2
  37. data/spec/lib/pact_broker/api/resources/verifications_spec.rb +7 -3
  38. data/spec/lib/pact_broker/db/clean_incremental_spec.rb +9 -1
  39. data/spec/lib/pact_broker/db/delete_overwritten_data_spec.rb +71 -11
  40. data/spec/lib/pact_broker/domain/tag_spec.rb +23 -9
  41. data/spec/lib/pact_broker/domain/verification_spec.rb +49 -0
  42. data/spec/lib/pact_broker/metrics/service_spec.rb +4 -1
  43. data/spec/lib/pact_broker/pacts/repository_spec.rb +54 -7
  44. data/spec/migrations/change_migration_strategy_spec.rb +1 -1
  45. metadata +12 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a7fe157577be6cdfb603e4607b174224781db0b9b2ee7ccb1325cdda50ce129d
4
- data.tar.gz: 9e28ef38f281ac6d6dbf1879d3794a8f915cb78bb8a82c464c7273ac9f8522dc
3
+ metadata.gz: f848cc7a613de4d084d69d97bf1b835c1d1bb130eec3c4c968800e348daf95bf
4
+ data.tar.gz: 1cbbbd2832eb98cd3904bba8aff8d909a95663c70abe7ad710473e46b3fb3e7c
5
5
  SHA512:
6
- metadata.gz: 3e5d4d249f691a3e03725e3b827f4044eb2fde360cd0dd9128fce61a4442288083f825f654473cf1a3220745460675036951242cc801211eda258369e38eeb09
7
- data.tar.gz: f8b9f3bdbfe42ca21291b41588ae4b3be15ca53efaec275e5356d8363dfa181e592942cb5e13bbd492fadb61d231cee68aaed009fef559c0645bc4debc4137c1
6
+ metadata.gz: 2200189e21700c21b67e1f8abc85574c3ed9367287568ce7dab4f808cd81ae01a80acd60fe3309cb134cd4466d2c243244429073d4e3af53b6b009bc58848782
7
+ data.tar.gz: c304534b3125112f4bd2bead0509e7e711face5f0e84ec88594cae1eb6e14a1618a4e61884ffbb0f66dbd813c4e5d4ebd61867ce276120a471a6a77f4c1e6e61
@@ -51,24 +51,4 @@ jobs:
51
51
  ruby_version: ["2.7"]
52
52
  steps:
53
53
  - uses: actions/checkout@v2
54
- - uses: actions/setup-ruby@v1
55
- with:
56
- ruby-version: ${{ matrix.ruby_version }}
57
- - uses: mirromutth/mysql-action@v1.1
58
- with:
59
- host port: 3306 # Optional, default value is 3306. The port of host
60
- #container port: 3307 # Optional, default value is 3306. The port of container
61
- character set server: 'utf8' # Optional, default value is 'utf8mb4'. The '--character-set-server' option for mysqld
62
- collation server: 'utf8_general_ci' # Optional, default value is 'utf8mb4_general_ci'. The '--collation-server' option for mysqld
63
- mysql version: '8.0' # Optional, default value is "latest". The version of the MySQL
64
- mysql database: 'pact_broker' # Optional, default value is "test". The specified database which will be create
65
- mysql root password: 'pact_broker' # Required if "mysql user" is empty, default is empty. The root superuser password
66
- mysql user: 'pact_broker' # Required if "mysql root password" is empty, default is empty. The superuser for the specified database. Can use secrets, too
67
- mysql password: 'pact_broker' # Required if "mysql user" exists. The password for the "mysql user"
68
- - run: "bundle install"
69
- env:
70
- INSTALL_MYSQL: "true"
71
- - run: "bundle exec rake"
72
- env:
73
- DATABASE_ADAPTER: github_actions_mysql
74
- INSTALL_MYSQL: "true"
54
+ - run: script/test/run-rake-on-docker-compose-mysql.sh
@@ -1,3 +1,14 @@
1
+ <a name="v2.72.0"></a>
2
+ ### v2.72.0 (2020-12-02)
3
+
4
+ #### Features
5
+
6
+ * allow overwritten data deletion to be configured with extra options ([fd809737](/../../commit/fd809737))
7
+ * use the consumer version number in the metadata to select the correct consumer version for a pact version resource ([422c87fc](/../../commit/422c87fc))
8
+ * return link to latest pact if more pacts exist when deleting pacts by tag ([b87ea704](/../../commit/b87ea704))
9
+ * update output for clean dry run ([681a5ddd](/../../commit/681a5ddd))
10
+ * update metrics output ([0617e9df](/../../commit/0617e9df))
11
+
1
12
  <a name="v2.71.0"></a>
2
13
  ### v2.71.0 (2020-11-28)
3
14
 
data/Dockerfile CHANGED
@@ -26,7 +26,7 @@ RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSI
26
26
 
27
27
 
28
28
  COPY Gemfile /home/Gemfile
29
- COPY Gemfile.lock /home/Gemfile.lock
29
+ # COPY Gemfile.lock /home/Gemfile.lock # lock file does not exist on CI
30
30
  COPY pact_broker.gemspec /home/pact_broker.gemspec
31
31
  COPY lib/pact_broker/version.rb /home/lib/pact_broker/version.rb
32
32
  COPY .gitignore /home/.gitignore
@@ -38,6 +38,10 @@ RUN echo '#!/bin/sh' >> /usr/local/bin/start
38
38
  RUN echo 'bundle exec rackup -o 0.0.0.0 -p 9292' >> /usr/local/bin/start
39
39
  RUN chmod +x /usr/local/bin/start
40
40
 
41
+ RUN echo '#!/bin/sh' >> /usr/local/bin/test
42
+ RUN echo 'bundle exec rake' >> /usr/local/bin/test
43
+ RUN chmod +x /usr/local/bin/test
44
+
41
45
  RUN echo '#!/bin/sh' >> /home/init-db.sh
42
46
  RUN echo 'bundle exec rake db:prepare:test' >> /home/init-db.sh
43
47
  RUN chmod +x /home/init-db.sh
@@ -0,0 +1,37 @@
1
+ version: "3"
2
+
3
+ services:
4
+ mysql:
5
+ image: mysql:5.7.28
6
+ command: --default-authentication-plugin=mysql_native_password
7
+ environment:
8
+ MYSQL_ROOT_PASSWORD: pact_broker
9
+ MYSQL_DATABASE: pact_broker
10
+ MYSQL_USER: pact_broker
11
+ MYSQL_PASSWORD: pact_broker
12
+ ports:
13
+ - "3306:3306"
14
+
15
+ tests:
16
+ build: .
17
+ depends_on:
18
+ - mysql
19
+ environment:
20
+ DATABASE_ADAPTER: docker_compose_mysql
21
+ PACT_BROKER_HIDE_PACTFLOW_MESSAGES: 'true'
22
+ INSTALL_MYSQL: 'true'
23
+ volumes:
24
+ - ./lib:/home/lib
25
+ - ./spec:/home/spec
26
+ - ./db:/home/db
27
+ - ./config.ru:/home/config.ru
28
+ - ./tasks:/home/tasks
29
+ - ./Rakefile:/home/Rakefile
30
+ - ./config:/home/config
31
+ - ./.rspec:/home/.rspec
32
+ - ./.rubocop:/home/.rubocop
33
+ - ./.gitignore:/home/.gitignore
34
+ - ./public:/home/public
35
+ - ./script/docker-container/test.sh:/usr/local/bin/test
36
+ entrypoint: dockerize
37
+ command: --wait tcp://mysql:3306 -timeout 60s test
@@ -75,7 +75,7 @@ module PactBroker
75
75
  end
76
76
 
77
77
  def decode_pact_metadata(metadata)
78
- if metadata
78
+ if metadata && metadata != ''
79
79
  begin
80
80
  Rack::Utils.parse_nested_query(Base64.strict_decode64(metadata)).each_with_object({}) do | (k, v), new_hash |
81
81
  new_hash[k.to_sym] = v
@@ -116,6 +116,10 @@ module PactBroker
116
116
  "#{base_url}/pacts/provider/#{url_encode(provider_name)}/consumer/#{url_encode(consumer_name)}/versions"
117
117
  end
118
118
 
119
+ def tagged_pact_versions_url consumer_name, provider_name, tag, base_url = ""
120
+ "#{base_url}/pacts/provider/#{url_encode(provider_name)}/consumer/#{url_encode(consumer_name)}/tag/#{url_encode(tag)}"
121
+ end
122
+
119
123
  def integration_url consumer_name, provider_name, base_url = ""
120
124
  "#{base_url}/integrations/provider/#{url_encode(provider_name)}/consumer/#{url_encode(consumer_name)}"
121
125
  end
@@ -0,0 +1,23 @@
1
+ require 'pact_broker/hash_refinements'
2
+
3
+ module PactBroker
4
+ module Api
5
+ module Resources
6
+ module MetadataResourceMethods
7
+ using PactBroker::HashRefinements
8
+
9
+ def pact_params
10
+ @pact_params ||= PactBroker::Pacts::PactParams.from_request(request, maybe_params_with_consumer_version_number.merge(path_info))
11
+ end
12
+
13
+ def maybe_params_with_consumer_version_number
14
+ metadata.slice(:consumer_version_number)
15
+ end
16
+
17
+ def metadata
18
+ @metadata ||= PactBrokerUrls.decode_pact_metadata(identifier_from_path[:metadata])
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -8,6 +8,7 @@ require 'pact_broker/pacts/pact_params'
8
8
  require 'pact_broker/api/contracts/put_pact_params_contract'
9
9
  require 'pact_broker/webhooks/execution_configuration'
10
10
  require 'pact_broker/api/resources/webhook_execution_methods'
11
+ require 'pact_broker/api/resources/pact_resource_methods'
11
12
 
12
13
  module PactBroker
13
14
  module Api
@@ -15,6 +16,7 @@ module PactBroker
15
16
  class Pact < BaseResource
16
17
  include PacticipantResourceMethods
17
18
  include WebhookExecutionMethods
19
+ include PactResourceMethods
18
20
 
19
21
  def content_types_provided
20
22
  [
@@ -110,19 +112,6 @@ module PactBroker
110
112
  @pact_params ||= PactBroker::Pacts::PactParams.from_request request, path_info
111
113
  end
112
114
 
113
- def set_post_deletion_response
114
- latest_pact = pact_service.find_latest_pact(pact_params)
115
- response_body = { "_links" => { index: { href: base_url } } }
116
- if latest_pact
117
- response_body["_links"]["pb:latest-pact-version"] = {
118
- href: latest_pact_url(base_url, latest_pact),
119
- title: "Latest pact"
120
- }
121
- end
122
- response.body = response_body.to_json
123
- response.headers["Content-Type" => "application/hal+json;charset=utf-8"]
124
- end
125
-
126
115
  def webhook_options
127
116
  {
128
117
  database_connector: database_connector,
@@ -0,0 +1,23 @@
1
+ module PactBroker
2
+ module Api
3
+ module Resources
4
+ module PactResourceMethods
5
+ def set_post_deletion_response
6
+ latest_pact = pact_service.find_latest_pact(
7
+ consumer_name: pact_params[:consumer_name],
8
+ provider_name: pact_params[:provider_name]
9
+ )
10
+ response_body = { "_links" => { index: { href: base_url } } }
11
+ if latest_pact
12
+ response_body["_links"]["pb:latest-pact-version"] = {
13
+ href: latest_pact_url(base_url, latest_pact),
14
+ title: "Latest pact"
15
+ }
16
+ end
17
+ response.body = response_body.to_json
18
+ response.headers["Content-Type" => "application/hal+json;charset=utf-8"]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,9 +1,12 @@
1
1
  require 'pact_broker/api/resources/pact'
2
+ require 'pact_broker/api/resources/metadata_resource_methods'
2
3
 
3
4
  module PactBroker
4
5
  module Api
5
6
  module Resources
6
7
  class PactVersion < Pact
8
+ include MetadataResourceMethods
9
+
7
10
  def allowed_methods
8
11
  ["GET", "OPTIONS"]
9
12
  end
@@ -1,11 +1,14 @@
1
1
  require 'pact_broker/api/resources/base_resource'
2
2
  require 'pact_broker/configuration'
3
3
  require 'pact_broker/api/decorators/tagged_pact_versions_decorator'
4
+ require 'pact_broker/api/resources/pact_resource_methods'
4
5
 
5
6
  module PactBroker
6
7
  module Api
7
8
  module Resources
8
9
  class TaggedPactVersions < BaseResource
10
+ include PactResourceMethods
11
+
9
12
  def content_types_provided
10
13
  [["application/hal+json", :to_json]]
11
14
  end
@@ -24,6 +27,7 @@ module PactBroker
24
27
 
25
28
  def delete_resource
26
29
  pact_service.delete_all_pact_publications_between consumer_name, and: provider_name, tag: identifier_from_path[:tag]
30
+ set_post_deletion_response
27
31
  true
28
32
  end
29
33
 
@@ -4,12 +4,14 @@ require 'pact_broker/domain/verification'
4
4
  require 'pact_broker/api/contracts/verification_contract'
5
5
  require 'pact_broker/api/decorators/verification_decorator'
6
6
  require 'pact_broker/api/resources/webhook_execution_methods'
7
+ require 'pact_broker/api/resources/metadata_resource_methods'
7
8
 
8
9
  module PactBroker
9
10
  module Api
10
11
  module Resources
11
12
  class Verifications < BaseResource
12
13
  include WebhookExecutionMethods
14
+ include MetadataResourceMethods
13
15
 
14
16
  def content_types_accepted
15
17
  [["application/json", :from_json]]
@@ -75,10 +77,6 @@ module PactBroker
75
77
  PactBroker::Api::Decorators::VerificationDecorator.new(model)
76
78
  end
77
79
 
78
- def metadata
79
- PactBrokerUrls.decode_pact_metadata(identifier_from_path[:metadata])
80
- end
81
-
82
80
  def wip?
83
81
  metadata[:wip] == 'true'
84
82
  end
@@ -43,35 +43,20 @@ module PactBroker
43
43
  end
44
44
 
45
45
  def version_ids_to_keep
46
- @version_ids_to_keep ||= keep.collect do | selector |
46
+ @version_ids_to_keep ||= selected_versions_to_keep.reduce(&:union)
47
+ end
48
+
49
+ def selected_versions_to_keep
50
+ keep.collect do | selector |
47
51
  PactBroker::Domain::Version.select(:id).for_selector(selector)
48
- end.reduce(&:union)
52
+ end
49
53
  end
50
54
 
51
55
  def call
52
56
  require 'pact_broker/db/models'
53
57
 
54
58
  if dry_run?
55
- to_delete = PactBroker::Domain::Version
56
- .where(id: version_ids_to_delete.select(:id))
57
- .all
58
- .group_by{ | v | v.pacticipant_id }
59
- .each_with_object({}) do | (pacticipant_id, versions), thing |
60
- thing[versions.first.pacticipant.name] = {
61
- count: versions.count,
62
- from_version: {
63
- number: versions.first.number,
64
- created: DateHelper.distance_of_time_in_words(versions.first.created_at, DateTime.now) + " ago",
65
- tags: versions.first.tags.collect(&:name)
66
- },
67
- to_version: {
68
- number: versions.last.number,
69
- created: DateHelper.distance_of_time_in_words(versions.last.created_at, DateTime.now) + " ago",
70
- tags: versions.last.tags.collect(&:name)
71
- }
72
- }
73
- end
74
- { "to_delete" => to_delete }
59
+ dry_run_results
75
60
  else
76
61
  before_counts = current_counts
77
62
  result = PactBroker::Domain::Version.where(id: resolve_ids(version_ids_to_delete)).delete
@@ -102,6 +87,131 @@ module PactBroker
102
87
  referenced_pact_version_ids = db[:pact_publications].select(:pact_version_id).union(db[:verifications].select(:pact_version_id))
103
88
  db[:pact_versions].where(id: referenced_pact_version_ids).invert.delete
104
89
  end
90
+
91
+ def version_info(version)
92
+ {
93
+ "number" => version.number,
94
+ "created" => DateHelper.distance_of_time_in_words(version.created_at, DateTime.now) + " ago",
95
+ "tags" => version.tags.collect(&:name).sort
96
+ }
97
+ end
98
+
99
+ def dry_run_results
100
+ to_delete = dry_run_to_delete
101
+ to_keep = dry_run_to_keep
102
+
103
+ kept_per_selector = keep.collect do | selector |
104
+ {
105
+ selector: selector.to_hash,
106
+ count: PactBroker::Domain::Version.for_selector(selector).count
107
+ }
108
+ end
109
+
110
+ pacticipant_results = pacticipants.each_with_object({}) do | pacticipant, results |
111
+ results[pacticipant.name] = {
112
+ "toDelete" => to_delete[pacticipant.name] || { "count" => 0 },
113
+ "toKeep" => to_keep[pacticipant.id]
114
+ }
115
+ end
116
+
117
+ total_versions_count = PactBroker::Domain::Version.count
118
+ versions_to_keep_count = version_ids_to_keep.count
119
+ versions_to_delete_count = version_ids_to_delete.count
120
+
121
+ {
122
+ "counts" => {
123
+ "totalVersions" => total_versions_count,
124
+ "versionsToDelete" => versions_to_delete_count,
125
+ "versionsNotToKeep" => total_versions_count - versions_to_keep_count,
126
+ "versionsToKeep" => versions_to_keep_count,
127
+ "versionsToKeepBySelector" => kept_per_selector,
128
+ },
129
+ "versionSummary" => pacticipant_results
130
+ }
131
+ end
132
+
133
+ def dry_run_latest_versions_to_keep
134
+ latest_undeleted_versions_by_order = PactBroker::Domain::Version.where(id: version_ids_to_delete.select(:id))
135
+ .invert
136
+ .select_group(:pacticipant_id)
137
+ .select_append{ max(order).as(latest_order) }
138
+
139
+ lv_versions_join = {
140
+ Sequel[:lv][:latest_order] => Sequel[:versions][:order],
141
+ Sequel[:lv][:pacticipant_id] => Sequel[:versions][:pacticipant_id]
142
+ }
143
+
144
+ PactBroker::Domain::Version
145
+ .select_all_qualified
146
+ .join(latest_undeleted_versions_by_order, lv_versions_join, { table_alias: :lv })
147
+ end
148
+
149
+ def dry_run_earliest_versions_to_keep
150
+ earliest_undeleted_versions_by_order = PactBroker::Domain::Version.where(id: version_ids_to_delete.select(:id))
151
+ .invert
152
+ .select_group(:pacticipant_id)
153
+ .select_append{ min(order).as(first_order) }
154
+
155
+ ev_versions_join = {
156
+ Sequel[:lv][:first_order] => Sequel[:versions][:order],
157
+ Sequel[:lv][:pacticipant_id] => Sequel[:versions][:pacticipant_id]
158
+ }
159
+
160
+ PactBroker::Domain::Version
161
+ .select_all_qualified
162
+ .join(earliest_undeleted_versions_by_order, ev_versions_join, { table_alias: :lv })
163
+ end
164
+
165
+ def dry_run_to_delete
166
+ PactBroker::Domain::Version
167
+ .where(id: version_ids_to_delete.select(:id))
168
+ .all
169
+ .group_by{ | v | v.pacticipant_id }
170
+ .each_with_object({}) do | (pacticipant_id, versions), thing |
171
+ thing[versions.first.pacticipant.name] = {
172
+ "count" => versions.count,
173
+ "fromVersion" => version_info(versions.first),
174
+ "toVersion" => version_info(versions.last)
175
+ }
176
+ end
177
+ end
178
+
179
+ def dry_run_to_keep
180
+ latest_to_keep = dry_run_latest_versions_to_keep.eager(:tags).each_with_object({}) do | version, r |
181
+ r[version.pacticipant_id] = {
182
+ "firstVersion" => version_info(version)
183
+ }
184
+ end
185
+
186
+ earliest_to_keep = dry_run_earliest_versions_to_keep.eager(:tags).each_with_object({}) do | version, r |
187
+ r[version.pacticipant_id] = {
188
+ "latestVersion" => version_info(version)
189
+ }
190
+ end
191
+
192
+ counts = counts_to_keep
193
+
194
+ pacticipants.collect(&:id).each_with_object({}) do | pacticipant_id, results |
195
+ results[pacticipant_id] = { "count" => counts[pacticipant_id] || 0 }
196
+ .merge(earliest_to_keep[pacticipant_id] || {})
197
+ .merge(latest_to_keep[pacticipant_id] || {})
198
+ end
199
+ end
200
+
201
+ def counts_to_keep
202
+ db[:versions].where(id: version_ids_to_delete.select(:id))
203
+ .invert
204
+ .select_group(:pacticipant_id)
205
+ .select_append{ count(1).as(count) }
206
+ .all
207
+ .each_with_object({}) do | row, counts |
208
+ counts[row[:pacticipant_id]] = row[:count]
209
+ end
210
+ end
211
+
212
+ def pacticipants
213
+ @pacticipants ||= PactBroker::Domain::Pacticipant.order_ignore_case(:name).all
214
+ end
105
215
  end
106
216
  end
107
217
  end