pact_broker 2.76.2 → 2.77.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +12 -0
  3. data/.github/workflows/test-ruby-3.yml +19 -0
  4. data/.github/workflows/test.yml +16 -7
  5. data/.gitignore +3 -1
  6. data/CHANGELOG.md +15 -0
  7. data/DEVELOPER_SETUP.md +62 -3
  8. data/Dockerfile +1 -0
  9. data/ISSUES.md +7 -7
  10. data/config.ru +1 -0
  11. data/db/ddl_statements/head_pact_tags.rb +24 -1
  12. data/db/ddl_statements/latest_tagged_pact_consumer_version_orders.rb +11 -0
  13. data/db/ddl_statements/latest_tagged_pact_publications.rb +6 -0
  14. data/db/ddl_statements/latest_verification_ids_for_consumer_version_tags.rb +13 -0
  15. data/db/migrations/20210117_add_branch_to_version.rb +9 -0
  16. data/db/migrations/20210202_add_created_at_to_head_pact_tags.rb +14 -0
  17. data/db/migrations/20210205_add_pacticipant_id_to_tag.rb +17 -0
  18. data/db/migrations/20210206_add_index_to_tags_and_versions.rb +27 -0
  19. data/db/migrations/20210207_optimise_latest_verification_ids_for_consumer_version_tags.rb +13 -0
  20. data/db/migrations/20210208_optimise_latest_tagged_pact_cv_orders.rb +13 -0
  21. data/lib/pact_broker/api.rb +2 -2
  22. data/lib/pact_broker/api/decorators/dashboard_decorator.rb +5 -1
  23. data/lib/pact_broker/api/decorators/matrix_decorator.rb +3 -1
  24. data/lib/pact_broker/api/decorators/verifiable_pacts_query_decorator.rb +2 -0
  25. data/lib/pact_broker/api/decorators/version_decorator.rb +4 -2
  26. data/lib/pact_broker/api/resources/default_base_resource.rb +4 -0
  27. data/lib/pact_broker/api/resources/index.rb +6 -0
  28. data/lib/pact_broker/api/resources/latest_version.rb +27 -0
  29. data/lib/pact_broker/api/resources/provider_pacts_for_verification.rb +1 -0
  30. data/lib/pact_broker/api/resources/version.rb +15 -9
  31. data/lib/pact_broker/certificates/certificate.rb +1 -1
  32. data/lib/pact_broker/config/setting.rb +1 -1
  33. data/lib/pact_broker/config/space_delimited_integer_list.rb +25 -0
  34. data/lib/pact_broker/configuration.rb +17 -1
  35. data/lib/pact_broker/db/data_migrations/helpers.rb +4 -0
  36. data/lib/pact_broker/db/data_migrations/set_extra_columns_for_tags.rb +29 -0
  37. data/lib/pact_broker/db/migrate_data.rb +1 -0
  38. data/lib/pact_broker/db/seed_example_data.rb +13 -13
  39. data/lib/pact_broker/doc/views/index/pacticipant-version.markdown +13 -0
  40. data/lib/pact_broker/domain/index_item.rb +18 -4
  41. data/lib/pact_broker/domain/pacticipant.rb +9 -5
  42. data/lib/pact_broker/domain/tag.rb +131 -71
  43. data/lib/pact_broker/domain/verification.rb +3 -2
  44. data/lib/pact_broker/domain/version.rb +58 -23
  45. data/lib/pact_broker/domain/webhook.rb +6 -3
  46. data/lib/pact_broker/index/service.rb +55 -49
  47. data/lib/pact_broker/matrix/quick_row.rb +8 -0
  48. data/lib/pact_broker/metrics/service.rb +1 -1
  49. data/lib/pact_broker/pacts/eager_loaders.rb +52 -0
  50. data/lib/pact_broker/pacts/latest_pact_publication_id_for_consumer_version.rb +18 -13
  51. data/lib/pact_broker/pacts/lazy_loaders.rb +14 -0
  52. data/lib/pact_broker/pacts/pact_publication.rb +38 -84
  53. data/lib/pact_broker/pacts/pact_publication_dataset_module.rb +297 -0
  54. data/lib/pact_broker/pacts/pact_version.rb +1 -2
  55. data/lib/pact_broker/pacts/pacts_for_verification_repository.rb +286 -0
  56. data/lib/pact_broker/pacts/repository.rb +5 -240
  57. data/lib/pact_broker/pacts/selected_pact.rb +4 -0
  58. data/lib/pact_broker/pacts/selector.rb +56 -1
  59. data/lib/pact_broker/pacts/selectors.rb +16 -0
  60. data/lib/pact_broker/pacts/service.rb +2 -6
  61. data/lib/pact_broker/pacts/squash_pacts_for_verification.rb +1 -4
  62. data/lib/pact_broker/pacts/verifiable_pact.rb +23 -2
  63. data/lib/pact_broker/pacts/verifiable_pact_messages.rb +56 -16
  64. data/lib/pact_broker/repositories/helpers.rb +4 -0
  65. data/lib/pact_broker/tags/eager_loaders.rb +47 -0
  66. data/lib/pact_broker/tags/repository.rb +3 -1
  67. data/lib/pact_broker/tags/service.rb +0 -3
  68. data/lib/pact_broker/tags/tag_with_latest_flag.rb +1 -0
  69. data/lib/pact_broker/test/http_test_data_builder.rb +23 -7
  70. data/lib/pact_broker/test/test_data_builder.rb +36 -3
  71. data/lib/pact_broker/ui/view_models/index_item.rb +9 -0
  72. data/lib/pact_broker/ui/view_models/matrix_line.rb +36 -0
  73. data/lib/pact_broker/ui/views/index/show-with-tags.haml +8 -0
  74. data/lib/pact_broker/ui/views/matrix/show.haml +10 -0
  75. data/lib/pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version.rb +7 -5
  76. data/lib/pact_broker/version.rb +1 -1
  77. data/lib/pact_broker/versions/eager_loaders.rb +71 -0
  78. data/lib/pact_broker/versions/lazy_loaders.rb +13 -0
  79. data/lib/pact_broker/versions/repository.rb +11 -2
  80. data/lib/pact_broker/versions/service.rb +5 -1
  81. data/lib/pact_broker/webhooks/execution.rb +3 -2
  82. data/lib/pact_broker/webhooks/latest_triggered_webhook.rb +2 -0
  83. data/lib/pact_broker/webhooks/triggered_webhook.rb +11 -4
  84. data/lib/pact_broker/webhooks/webhook.rb +1 -1
  85. data/lib/pact_broker/webhooks/webhook_event.rb +1 -1
  86. data/lib/pact_broker/webhooks/webhook_request_logger.rb +5 -1
  87. data/lib/sequel/plugins/upsert.rb +18 -4
  88. data/public/stylesheets/index.css +22 -1
  89. data/public/stylesheets/matrix.css +0 -21
  90. data/regression/can_i_deploy_spec.rb +5 -4
  91. data/regression/index_spec.rb +26 -0
  92. data/regression/regression_helper.rb +29 -3
  93. data/regression/script/clear.sh +3 -0
  94. data/regression/script/run.sh +3 -0
  95. data/script/demonstrate-version-branches.rb +33 -0
  96. data/script/pry.rb +2 -2
  97. data/spec/features/create_version_spec.rb +44 -0
  98. data/spec/fixtures/dashboard.json +4 -2
  99. data/spec/lib/pact_broker/api/decorators/dashboard_decorator_spec.rb +4 -2
  100. data/spec/lib/pact_broker/api/decorators/matrix_decorator_spec.rb +11 -6
  101. data/spec/lib/pact_broker/api/decorators/verifiable_pacts_query_decorator_spec.rb +6 -0
  102. data/spec/lib/pact_broker/api/resources/provider_pacts_for_verification_spec.rb +4 -0
  103. data/spec/lib/pact_broker/config/space_delimited_integer_list_spec.rb +47 -0
  104. data/spec/lib/pact_broker/configuration_spec.rb +12 -0
  105. data/spec/lib/pact_broker/domain/tag_spec.rb +101 -27
  106. data/spec/lib/pact_broker/domain/version_spec.rb +103 -15
  107. data/spec/lib/pact_broker/domain/webhook_spec.rb +1 -1
  108. data/spec/lib/pact_broker/index/service_spec.rb +89 -15
  109. data/spec/lib/pact_broker/pacts/pact_publication_dataset_module_spec.rb +400 -0
  110. data/spec/lib/pact_broker/pacts/pact_publication_spec.rb +434 -14
  111. data/spec/lib/pact_broker/pacts/repository_find_for_verification_fallback_spec.rb +1 -1
  112. data/spec/lib/pact_broker/pacts/repository_find_for_verification_spec.rb +1 -1
  113. data/spec/lib/pact_broker/pacts/repository_find_wip_pact_versions_for_provider_branch_spec.rb +224 -0
  114. data/spec/lib/pact_broker/pacts/repository_find_wip_pact_versions_for_provider_spec.rb +20 -7
  115. data/spec/lib/pact_broker/pacts/selector_spec.rb +3 -2
  116. data/spec/lib/pact_broker/pacts/service_find_for_verification_spec.rb +2 -3
  117. data/spec/lib/pact_broker/pacts/service_spec.rb +2 -2
  118. data/spec/lib/pact_broker/pacts/verifiable_pact_messages_spec.rb +57 -10
  119. data/spec/lib/pact_broker/tags/repository_spec.rb +2 -0
  120. data/spec/lib/pact_broker/versions/repository_spec.rb +44 -0
  121. data/spec/lib/pact_broker/webhooks/webhook_request_logger_spec.rb +8 -0
  122. data/spec/lib/sequel/plugins/upsert_spec.rb +31 -3
  123. data/spec/spec_helper.rb +17 -5
  124. data/spec/support/approvals.rb +24 -0
  125. data/tasks/db.rake +1 -0
  126. data/tasks/rspec.rake +1 -1
  127. metadata +36 -3
@@ -60,6 +60,18 @@ module PactBroker
60
60
  end
61
61
  end
62
62
 
63
+ describe "webhook_http_code_success" do
64
+ it "allows setting the 'webhook_http_code_success' by a space-delimited string" do
65
+ PactBroker.configuration.webhook_http_code_success = "200 201 202"
66
+ expect(PactBroker.configuration.webhook_http_code_success).to be_a Config::SpaceDelimitedIntegerList
67
+ end
68
+
69
+ it "allows setting the 'webhook_http_code_success' by an array" do
70
+ PactBroker.configuration.webhook_http_code_success = [200, 201, 202]
71
+ expect(PactBroker.configuration.webhook_http_code_success).to be_a Config::SpaceDelimitedIntegerList
72
+ end
73
+ end
74
+
63
75
  describe "webhook_scheme_whitelist" do
64
76
  it "allows setting the whitelist by a string" do
65
77
  PactBroker.configuration.webhook_scheme_whitelist = "foo"
@@ -3,22 +3,23 @@ require 'pact_broker/domain/tag'
3
3
  module PactBroker
4
4
  module Domain
5
5
  describe Tag do
6
- before do
7
- td.create_consumer("foo")
8
- .create_consumer_version("1")
9
- .create_consumer_version_tag("dev")
10
- .create_consumer_version_tag("prod")
11
- .create_consumer_version("2")
12
- .create_consumer_version_tag("dev")
13
- .create_consumer_version_tag("bloop")
14
- .create_consumer_version("3")
15
- .create_consumer_version_tag("dev")
16
- .create_consumer("bar")
17
- .create_consumer_version("1")
18
- .create_consumer_version_tag("test")
19
- end
20
6
 
21
7
  describe "#latest_tags_for_pacticipant_ids" do
8
+ before do
9
+ td.create_consumer("foo")
10
+ .create_consumer_version("1")
11
+ .create_consumer_version_tag("dev")
12
+ .create_consumer_version_tag("prod")
13
+ .create_consumer_version("2")
14
+ .create_consumer_version_tag("dev")
15
+ .create_consumer_version_tag("bloop")
16
+ .create_consumer_version("3")
17
+ .create_consumer_version_tag("dev")
18
+ .create_consumer("bar")
19
+ .create_consumer_version("1")
20
+ .create_consumer_version_tag("test")
21
+ end
22
+
22
23
  it "returns the latest tags for the given pacticipant ids" do
23
24
  pacticipant = PactBroker::Domain::Pacticipant.order(:id).first
24
25
  tags = Tag.latest_tags_for_pacticipant_ids([pacticipant.id]).all
@@ -32,6 +33,21 @@ module PactBroker
32
33
  end
33
34
 
34
35
  describe "latest_tags" do
36
+ before do
37
+ td.create_consumer("foo")
38
+ .create_consumer_version("1")
39
+ .create_consumer_version_tag("dev")
40
+ .create_consumer_version_tag("prod")
41
+ .create_consumer_version("2")
42
+ .create_consumer_version_tag("dev")
43
+ .create_consumer_version_tag("bloop")
44
+ .create_consumer_version("3")
45
+ .create_consumer_version_tag("dev")
46
+ .create_consumer("bar")
47
+ .create_consumer_version("1")
48
+ .create_consumer_version_tag("test")
49
+ end
50
+
35
51
  it "returns the tags that belong to the most recent version with that tag/pacticipant" do
36
52
  tags = Tag.latest_tags.all
37
53
  expect(tags.collect(&:name).sort).to eq %w{bloop dev prod test}
@@ -42,19 +58,77 @@ module PactBroker
42
58
  expect(tags.collect(&:created_at).compact.size).to eq 4
43
59
  end
44
60
  end
61
+
62
+ describe "latest_for_pacticipant?" do
63
+ before do
64
+ # Foo v1 Bar1
65
+ # Foo v1 Bar2
66
+ # Foo v2 Bar1
67
+ td.create_pact_with_verification_and_tags("Foo", "1", ["dev", "prod"], "Bar1")
68
+ .create_provider("Bar2")
69
+ .create_pact
70
+ .create_pact_with_verification_and_tags("Foo", "2", ["dev"], "Bar1")
71
+ .create_consumer_version("3")
72
+ .create_consumer_version_tag("dev")
73
+ end
74
+
75
+ it "returns true if there are no other tags with that name for that pacticipant for a later version" do
76
+ version_1 = PactBroker::Versions::Repository.new.find_by_pacticipant_name_and_number("Foo", "1")
77
+ expect(version_1.tags.find { |t| t.name == "prod" }.latest_for_pacticipant?).to be true
78
+ expect(version_1.tags.find { |t| t.name == "dev" }.latest_for_pacticipant?).to be false
79
+ end
80
+ end
81
+
82
+ describe "head_tags_for_pact_publication" do
83
+ before do
84
+ # Foo v1 Bar1
85
+ # Foo v1 Bar2
86
+ # Foo v2 Bar1
87
+ td.create_pact_with_verification_and_tags("Foo", "1", ["dev", "prod"], "Bar1")
88
+ .create_provider("Bar2")
89
+ .create_pact
90
+ .create_pact_with_verification_and_tags("Foo", "2", ["dev"], "Bar1")
91
+ .create_consumer_version("3")
92
+ .create_consumer_version_tag("dev")
93
+ end
94
+
95
+ it "returns the names of the tags for which this pact publication is the latest" do
96
+ pact_0 = PactBroker::Pacts::PactPublication.find(id: PactBroker::Pacts::Repository.new.find_pact("Foo", "1", "Bar1").id)
97
+ expect(pact_0.consumer_version.tags.collect(&:name).sort).to eq ["dev", "prod"]
98
+ expect(Tag.head_tags_for_pact_publication(pact_0).collect(&:name).sort).to eq ["prod"]
99
+
100
+ pact_1 = PactBroker::Pacts::PactPublication.find(id: PactBroker::Pacts::Repository.new.find_pact("Foo", "2", "Bar1").id)
101
+ expect(Tag.head_tags_for_pact_publication(pact_1).collect(&:name).sort).to eq ["dev"]
102
+
103
+ pact_2 = PactBroker::Pacts::PactPublication.find(id: PactBroker::Pacts::Repository.new.find_pact("Foo", "1", "Bar2").id)
104
+ expect(Tag.head_tags_for_pact_publication(pact_2).collect(&:name).sort).to eq ["dev", "prod"]
105
+ end
106
+ end
107
+
108
+ describe "head_tag" do
109
+ before do
110
+ td.create_consumer("Foo")
111
+ .create_consumer_version("1", tag_names: ["main", "test"])
112
+ .create_consumer_version("2", tag_names: ["main", "test"])
113
+ .create_consumer_version("3", tag_names: ["main"])
114
+ .create_provider("Bar")
115
+ .create_provider_version("1", tag_names: ["main", "test"])
116
+ .create_provider_version("2", tag_names: ["main", "test"])
117
+ .create_provider_version("3", tag_names: ["main"])
118
+ end
119
+
120
+ it "lazy loads" do
121
+ expect(Tag.for("Foo", "2", "main").head_tag).to eq Tag.for("Foo", "3", "main")
122
+ expect(Tag.for("Foo", "3", "main").head_tag).to eq Tag.for("Foo", "3", "main")
123
+ expect(Tag.for("Bar", "1", "test").head_tag).to eq Tag.for("Bar", "2", "test")
124
+ end
125
+
126
+ it "eager loads" do
127
+ tags = Tag.order(:version_order, :name).eager(:head_tag).all
128
+ expect(tags[0].head_tag).to eq Tag.for("Foo", "3", "main")
129
+ expect(tags[1].head_tag).to eq Tag.for("Foo", "2", "test")
130
+ end
131
+ end
45
132
  end
46
133
  end
47
134
  end
48
-
49
- # Table: tags
50
- # Primary Key: (name, version_id)
51
- # Columns:
52
- # name | text |
53
- # version_id | integer |
54
- # created_at | timestamp without time zone | NOT NULL
55
- # updated_at | timestamp without time zone | NOT NULL
56
- # Indexes:
57
- # tags_pk | PRIMARY KEY btree (version_id, name)
58
- # ndx_tag_name | btree (name)
59
- # Foreign key constraints:
60
- # tags_version_id_fkey | (version_id) REFERENCES versions(id)
@@ -142,6 +142,88 @@ module PactBroker
142
142
  end
143
143
  end
144
144
 
145
+ describe "latest_for_pacticipant?" do
146
+ before do
147
+ td.create_consumer("Foo")
148
+ .create_consumer_version("1")
149
+ .create_consumer_version("2")
150
+ .create_consumer("Bar")
151
+ .create_consumer_version("5")
152
+ .create_consumer_version("6")
153
+ .create_consumer_version("7")
154
+ end
155
+
156
+ context "when the version is the latest for the pacticipant" do
157
+ it "returns true" do
158
+ expect(Version.for("Foo", "2").latest_for_pacticipant?).to be true
159
+ end
160
+ end
161
+
162
+ context "when the version is not the latest version for the pacticipant" do
163
+ it "returns false" do
164
+ expect(Version.for("Foo", "1").latest_for_pacticipant?).to be false
165
+ end
166
+ end
167
+ end
168
+
169
+ describe "latest_version_for_pacticipant" do
170
+ before do
171
+ td.create_consumer("Foo")
172
+ .create_consumer_version("1")
173
+ .create_consumer_version("2")
174
+ .create_consumer("Bar")
175
+ .create_consumer_version("5")
176
+ .create_consumer_version("6")
177
+ .create_consumer_version("7")
178
+ end
179
+
180
+ subject { Version.order(:order) }
181
+
182
+ it "lazy loads" do
183
+ expect(subject.all[0].latest_version_for_pacticipant.number).to eq "2"
184
+ end
185
+
186
+ it "eager loads" do
187
+ all = subject.eager(:latest_version_for_pacticipant).all
188
+ expect(all[0].associations[:latest_version_for_pacticipant]).to_not be nil
189
+ expect(all[0].latest_version_for_pacticipant.number).to eq "2"
190
+ end
191
+ end
192
+
193
+ describe "latest_version_for_branch" do
194
+ before do
195
+ td.create_consumer("Foo")
196
+ .create_consumer_version("1", branch: "main")
197
+ .create_consumer_version("2", branch: "main")
198
+ .create_consumer_version("3", branch: "feat/x")
199
+ .create_consumer_version("4", branch: "feat/x")
200
+ .create_consumer_version("5")
201
+ end
202
+
203
+ subject { Version.order(:order) }
204
+
205
+ it "lazy loads" do
206
+ expect(subject.all[0].latest_version_for_branch.number).to eq "2"
207
+ expect(subject.all[2].latest_version_for_branch.number).to eq "4"
208
+ expect(subject.all[4].latest_version_for_branch).to eq nil
209
+ end
210
+
211
+ it "eager loads" do
212
+ all = subject.eager(:latest_version_for_branch).all
213
+
214
+ expect(all[0].associations[:latest_version_for_branch]).to_not be nil
215
+ expect(all[1].associations[:latest_version_for_branch]).to_not be nil
216
+ expect(all[2].associations[:latest_version_for_branch]).to_not be nil
217
+ expect(all[3].associations[:latest_version_for_branch]).to_not be nil
218
+ expect(all[4].associations.fetch(:latest_version_for_branch)).to be nil
219
+
220
+ expect(all[0].latest_version_for_branch.number).to eq "2"
221
+ expect(all[1].latest_version_for_branch.number).to eq "2"
222
+ expect(all[2].latest_version_for_branch.number).to eq "4"
223
+ expect(all[4].latest_version_for_branch).to eq nil
224
+ end
225
+ end
226
+
145
227
  describe "#latest_pact_publication" do
146
228
  let!(:pact) do
147
229
  TestDataBuilder.new
@@ -173,26 +255,32 @@ module PactBroker
173
255
  end
174
256
  end
175
257
 
176
- describe "tags_with_latest_flag" do
258
+ describe "latest_for_branch?" do
177
259
  before do
178
- td.create_consumer("foo")
179
- .create_consumer_version("1")
180
- .create_consumer_version_tag("dev")
181
- .create_consumer_version_tag("prod")
182
- .create_consumer_version("2")
183
- .create_consumer_version_tag("dev")
260
+ td.create_consumer("Foo")
261
+ .create_consumer_version("1", branch: "main")
262
+ .create_consumer_version("2", branch: "main")
263
+ .create_consumer_version("3", branch: nil)
264
+ end
265
+
266
+ subject { version.latest_for_branch? }
267
+
268
+ context "when there is a later version with the same branch name" do
269
+ let(:version) { Version.for("Foo", "1") }
270
+
271
+ it { is_expected.to be false }
184
272
  end
185
273
 
186
- it "uneager loads" do
187
- version = Version.first(number: "1")
188
- expect(version.tags.collect(&:name).sort).to eq %w{dev prod}
189
- expect(version.tags_with_latest_flag.select(&:latest).collect(&:name)).to eq %w{prod}
274
+ context "when there is a later version with the same branch name" do
275
+ let(:version) { Version.for("Foo", "2") }
276
+
277
+ it { is_expected.to be true }
190
278
  end
191
279
 
192
- it "eager loads" do
193
- version = Version.eager(:tags, :tags_with_latest_flag).where(number: "1").all.first
194
- expect(version.tags.collect(&:name).sort).to eq %w{dev prod}
195
- expect(version.tags_with_latest_flag.select(&:latest).collect(&:name)).to eq %w{prod}
280
+ context "when there is no branch" do
281
+ let(:version) { Version.for("Foo", "3") }
282
+
283
+ it { is_expected.to be nil }
196
284
  end
197
285
  end
198
286
  end
@@ -11,7 +11,7 @@ module PactBroker
11
11
  let(:webhook_template_parameters) { instance_double(PactBroker::Webhooks::PactAndVerificationParameters, to_hash: webhook_template_parameters_hash) }
12
12
  let(:webhook_template_parameters_hash) { { 'foo' => 'bar' } }
13
13
  let(:http_request) { double('http request') }
14
- let(:http_response) { double('http response') }
14
+ let(:http_response) { double('http response', code: "200") }
15
15
  let(:event_context) { { some: 'things' } }
16
16
  let(:logging_options) { { other: 'options' } }
17
17
  let(:options) { { logging_options: logging_options } }
@@ -192,6 +192,43 @@ module PactBroker
192
192
  expect(rows[1].provider_name).to eq "Wiffle"
193
193
  end
194
194
  end
195
+
196
+ context "with tags[]=" do
197
+ before do
198
+ td.create_pact_with_hierarchy("Foo", "1.0.0", "Bar")
199
+ .create_verification(provider_version: "4.5.6")
200
+ .create_consumer_version("2.0.0")
201
+ .create_consumer_version_tag("dev")
202
+ .create_pact
203
+ .revise_pact
204
+ .create_consumer_version("2.1.0")
205
+ .create_consumer_version_tag("prod")
206
+ .create_consumer_version_tag("not-prod")
207
+ .create_pact
208
+ .revise_pact
209
+ .create_verification(provider_version: "4.5.6", number: 1)
210
+ .create_verification(provider_version: "4.5.7", number: 2)
211
+ .create_verification(provider_version: "4.5.8", number: 3)
212
+ .create_verification(provider_version: "4.5.9", number: 4)
213
+ .create_provider("Wiffle")
214
+ .create_pact
215
+ end
216
+
217
+ let(:options) { {tags: ["prod"]} }
218
+
219
+ it "returns a row for for the latest pact and a row for the prod pact (maybe it shouldn't return the latest as well)" do
220
+ expect(rows.size).to eq 2
221
+
222
+ expect(rows[0].latest?).to be true
223
+ expect(rows[0].provider_name).to eq "Bar"
224
+ expect(rows[0].tag_names).to eq ["prod"]
225
+ expect(rows[0].provider_version_number).to eq "4.5.9"
226
+
227
+ expect(rows[1].latest?).to be true
228
+ expect(rows[1].provider_name).to eq "Wiffle"
229
+ expect(rows[1].tag_names).to eq ["prod"]
230
+ end
231
+ end
195
232
  end
196
233
 
197
234
  context "when a pact with a tag has been verified, and then a new changed version has been published with the same tag" do
@@ -263,29 +300,66 @@ module PactBroker
263
300
  let(:page_size) { 2 }
264
301
  let(:tags) { nil }
265
302
 
266
- before do
267
- td.create_pact_with_hierarchy("Foo1", "1", "Bar1")
268
- .create_pact_with_hierarchy("Foo2", "1", "Bar2")
269
- .create_pact_with_hierarchy("Foo3", "1", "Bar3")
270
- end
303
+ context "with no tags" do
304
+ before do
305
+ td.create_pact_with_hierarchy("Foo1", "1", "Bar1")
306
+ .create_pact_with_hierarchy("Foo2", "1", "Bar2")
307
+ .create_pact_with_hierarchy("Foo3", "1", "Bar3")
308
+ end
271
309
 
272
- it "it returns the total number of records" do
273
- expect(rows.pagination_record_count).to eq 3
274
- end
310
+ it "it returns the total number of records" do
311
+ expect(rows.pagination_record_count).to eq 3
312
+ end
275
313
 
276
- describe "the first page" do
277
- it "contains 2 rows" do
278
- expect(rows.count).to eq 2
314
+ describe "the first page" do
315
+ it "contains 2 rows" do
316
+ expect(rows.count).to eq 2
317
+ end
318
+ end
319
+
320
+ describe "the second page" do
321
+ let(:page_number) { 2 }
322
+
323
+ it "contains 1 row" do
324
+ expect(rows.count).to eq 1
325
+ end
279
326
  end
280
327
  end
281
328
 
282
- describe "the second page" do
283
- let(:page_number) { 2 }
329
+ context "with tags" do
330
+ before do
331
+ td.create_pact_with_hierarchy("Foo1", "1", "Bar1")
332
+ .create_consumer_version_tag("prod")
333
+ .create_consumer_version_tag("dev")
334
+ .create_pact_with_hierarchy("Foo2", "1", "Bar2")
335
+ .create_consumer_version_tag("prod")
336
+ .create_consumer_version_tag("dev")
337
+ .create_pact_with_hierarchy("Foo3", "1", "Bar3")
338
+ .create_consumer_version_tag("prod")
339
+ .create_consumer_version_tag("dev")
340
+ end
341
+
342
+ let(:tags) { true }
284
343
 
285
- it "contains 1 row" do
286
- expect(rows.count).to eq 1
344
+ it "it returns the total number of records" do
345
+ expect(rows.pagination_record_count).to eq 3
346
+ end
347
+
348
+ describe "the first page" do
349
+ it "contains 2 rows" do
350
+ expect(rows.count).to eq 2
351
+ end
352
+ end
353
+
354
+ describe "the second page" do
355
+ let(:page_number) { 2 }
356
+
357
+ it "contains 1 row" do
358
+ expect(rows.count).to eq 1
359
+ end
287
360
  end
288
361
  end
362
+
289
363
  end
290
364
  end
291
365
 
@@ -0,0 +1,400 @@
1
+ require 'pact_broker/pacts/pact_publication'
2
+
3
+ module PactBroker
4
+ module Pacts
5
+ describe PactPublication do
6
+ describe "latest_by_consumer_branch" do
7
+ before do
8
+ td.set_now(Date.new(2020, 1, 1))
9
+ .create_consumer("Foo")
10
+ .create_provider("Bar")
11
+ .create_consumer_version("1", branch: "main")
12
+ .create_pact
13
+ .set_now(Date.new(2020, 1, 2))
14
+ .create_consumer_version("2", branch: "feat/x")
15
+ .create_pact
16
+ .set_now(Date.new(2020, 1, 3))
17
+ .create_consumer_version("3", branch: "main", comment: "latest")
18
+ .create_pact
19
+ .set_now(Date.new(2020, 1, 4))
20
+ .create_consumer_version("4", branch: "feat/x", comment: "latest")
21
+ .create_pact
22
+ .set_now(Date.new(2020, 1, 5))
23
+ .create_consumer("FooZ")
24
+ .create_consumer_version("6", branch: "main", comment: "latest, different consumer")
25
+ .create_pact
26
+ .set_now(Date.new(2020, 1, 6))
27
+ .create_consumer_version("7", comment: "No branch")
28
+ .create_pact
29
+ .set_now(Date.new(2020, 1, 7))
30
+ .create_consumer_version("8", branch: "main", comment: "No pact")
31
+ end
32
+
33
+ subject { PactPublication.latest_by_consumer_branch.all }
34
+
35
+ let(:foo) { PactBroker::Domain::Pacticipant.where(name: "Foo").single_record }
36
+ let(:bar) { PactBroker::Domain::Pacticipant.where(name: "Bar").single_record }
37
+ let(:foo_z) { PactBroker::Domain::Pacticipant.where(name: "FooZ").single_record }
38
+
39
+ it "returns the latest pact publications for each consumer/branch" do
40
+ expect(subject.size).to eq 3
41
+
42
+ expect(subject.find { |pp| pp.consumer_id == foo.id && pp[:branch] == "main" }.consumer_version.number).to eq "3"
43
+ expect(subject.find { |pp| pp.consumer_id == foo.id && pp[:branch] == "feat/x" }.consumer_version.number).to eq "4"
44
+ expect(subject.find { |pp| pp.consumer_id == foo_z.id && pp[:branch] == "main" }.consumer_version.number).to eq "6"
45
+ end
46
+
47
+ it "does not return extra columns" do
48
+ expect(subject.first.values.keys.sort).to eq (PactPublication.columns + [:branch]).sort
49
+ end
50
+
51
+ context "chained with created after" do
52
+ subject { PactPublication.created_after(DateTime.new(2020, 1, 3)).latest_by_consumer_branch.all }
53
+
54
+ its(:size) { is_expected.to eq 2 }
55
+
56
+ it "returns the right versions" do
57
+ expect(subject.find { |pp| pp.consumer_id == foo.id && pp[:branch] == "feat/x" }.consumer_version.number).to eq "4"
58
+ expect(subject.find { |pp| pp.consumer_id == foo_z.id && pp[:branch] == "main" }.consumer_version.number).to eq "6"
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "latest_for_consumer_branch" do
64
+ before do
65
+ td.create_consumer("Foo")
66
+ .create_provider("Bar")
67
+ .create_consumer_version("1", branch: "main")
68
+ .create_pact
69
+ .create_consumer_version("2", branch: "main")
70
+ .create_pact
71
+ .create_consumer_version("3", branch: "feat-x")
72
+ .create_pact
73
+ .create_consumer("Foo2")
74
+ .create_provider("Bar2")
75
+ .create_consumer_version("10", branch: "main")
76
+ .create_pact
77
+ .create_consumer_version("11", branch: "main")
78
+ .create_pact
79
+ end
80
+
81
+ subject { PactPublication.latest_for_consumer_branch("main") }
82
+
83
+ it "returns the latest pacts for the branches with the specified name (for any consumer/provider)" do
84
+ all = subject.all.sort_by{ |pact_publication| pact_publication.consumer_version.order }
85
+ expect(all.size).to eq 2
86
+ expect(all.first.consumer.name).to eq "Foo"
87
+ expect(all.first.provider.name).to eq "Bar"
88
+ expect(all.first.consumer_version.number).to eq "2"
89
+
90
+ expect(all.last.consumer.name).to eq "Foo2"
91
+ expect(all.last.provider.name).to eq "Bar2"
92
+ expect(all.last.consumer_version.number).to eq "11"
93
+ end
94
+
95
+ it "does not return extra columns" do
96
+ expect(subject.first.values.keys.sort).to eq (PactPublication.columns + [:branch]).sort
97
+ end
98
+
99
+ context "when columns are already selected" do
100
+ subject { PactPublication.select(Sequel[:pact_publications][:id]).latest_for_consumer_branch("main") }
101
+
102
+ it "does not override them" do
103
+ expect(subject.all.first.values.keys).to eq [:id]
104
+ end
105
+ end
106
+
107
+ context "when chained" do
108
+ it "works" do
109
+ all = PactPublication.for_provider(td.find_pacticipant("Bar")).latest_for_consumer_branch("main").all
110
+ expect(all.first.provider.name).to eq "Bar"
111
+ end
112
+ end
113
+ end
114
+
115
+ describe "latest_by_consumer_tag" do
116
+ before do
117
+ td.create_consumer("Foo")
118
+ .create_provider("Bar")
119
+ .create_consumer_version("1", tag_names: ["main"])
120
+ .create_pact
121
+ .create_consumer_version("2", tag_names: ["feat/x"])
122
+ .create_pact
123
+ .create_consumer_version("3", tag_names: ["main"], comment: "latest")
124
+ .create_pact
125
+ .create_consumer_version("4", tag_names: ["feat/x"], comment: "latest")
126
+ .create_pact
127
+ .create_consumer("FooZ")
128
+ .create_consumer_version("6", tag_names: ["main"], comment: "Different consumer")
129
+ .create_pact
130
+ .create_consumer_version("7", comment: "No branch")
131
+ .create_pact
132
+ .create_consumer_version("8", tag_names: ["main"], comment: "No pact")
133
+ end
134
+
135
+ subject { PactPublication.latest_by_consumer_tag.all }
136
+
137
+ let(:foo) { PactBroker::Domain::Pacticipant.where(name: "Foo").single_record }
138
+ let(:bar) { PactBroker::Domain::Pacticipant.where(name: "Bar").single_record }
139
+ let(:foo_z) { PactBroker::Domain::Pacticipant.where(name: "FooZ").single_record }
140
+
141
+ it "returns the latest pact publications for each consumer/branch" do
142
+ expect(subject.size).to eq 3
143
+ hashes = subject.collect(&:values)
144
+
145
+ expect(subject.find { |pp| pp.consumer_id == foo.id && pp[:tag_name] == "main" }.consumer_version.number).to eq "3"
146
+ expect(subject.find { |pp| pp.consumer_id == foo.id && pp[:tag_name] == "feat/x" }.consumer_version.number).to eq "4"
147
+ expect(subject.find { |pp| pp.consumer_id == foo_z.id && pp[:tag_name] == "main" }.consumer_version.number).to eq "6"
148
+ end
149
+
150
+ it "does not return extra columns" do
151
+ expect(subject.first.values.keys.sort).to eq (PactPublication.columns + [:tag_name]).sort
152
+ end
153
+
154
+ context "when columns are already selected" do
155
+ subject { PactPublication.select(Sequel[:pact_publications][:id]).latest_by_consumer_tag }
156
+
157
+ it "does not override them" do
158
+ expect(subject.all.first.values.keys).to eq [:id]
159
+ end
160
+ end
161
+ end
162
+
163
+ describe "overall_latest" do
164
+ before do
165
+ td.create_consumer("Foo")
166
+ .create_provider("Bar")
167
+ .create_consumer_version("1", tag_names: ["main"])
168
+ .create_pact
169
+ .create_consumer_version("2", tag_names: ["main"])
170
+ .create_pact
171
+ .create_consumer_version("3", tag_names: ["feat/x"])
172
+ .create_pact
173
+ .create_consumer("Foo2")
174
+ .create_provider("Bar2")
175
+ .create_consumer_version("10", tag_names: ["main"])
176
+ .create_pact
177
+ .create_consumer_version("11", tag_names: ["main"])
178
+ .create_pact
179
+ end
180
+
181
+ subject { PactPublication.overall_latest }
182
+
183
+ it "returns the latest by consumer/provider" do
184
+ all = subject.all.sort_by{ | pact_publication | pact_publication.consumer_version.order }
185
+ expect(all.size).to eq 2
186
+ end
187
+
188
+ it "does not return extra columns" do
189
+ expect(subject.all.first.values.keys.sort).to eq PactPublication.columns.sort
190
+ end
191
+
192
+ context "when columns are already selected" do
193
+ subject { PactPublication.select(Sequel[:pact_publications][:id]).overall_latest }
194
+
195
+ it "does not override them" do
196
+ expect(subject.all.first.values.keys).to eq [:id]
197
+ end
198
+ end
199
+
200
+ context "when chained" do
201
+ it "works with a consumer" do
202
+ expect(PactPublication.for_consumer(td.find_pacticipant("Foo")).overall_latest.all.first.consumer.name).to eq "Foo"
203
+ end
204
+
205
+ it "works with a consumer and provider" do
206
+ td.create_pact_with_hierarchy("Foo", "666", "Nope")
207
+ all = PactPublication
208
+ .for_consumer(td.find_pacticipant("Foo"))
209
+ .for_provider(td.find_pacticipant("Bar"))
210
+ .overall_latest.all
211
+ expect(all.size).to eq 1
212
+ expect(all.first.consumer.name).to eq "Foo"
213
+ expect(all.first.provider.name).to eq "Bar"
214
+ end
215
+ end
216
+ end
217
+
218
+ describe "latest_for_consumer_tag" do
219
+ before do
220
+ td.create_consumer("Foo")
221
+ .create_provider("Bar")
222
+ .create_consumer_version("1", tag_names: ["main"])
223
+ .create_pact
224
+ .create_consumer_version("2", tag_names: ["main"])
225
+ .create_pact
226
+ .revise_pact
227
+ .create_consumer_version("3", tag_names: ["feat/x"])
228
+ .create_pact
229
+ .create_consumer("Foo2")
230
+ .create_provider("Bar2")
231
+ .create_consumer_version("10", tag_names: ["main"])
232
+ .create_pact
233
+ .create_consumer_version("11", tag_names: ["main"])
234
+ .create_pact
235
+ end
236
+
237
+ subject { PactPublication.latest_for_consumer_tag("main") }
238
+
239
+ it "returns the latest pacts for the tags with the specified name (for any consumer/provider)" do
240
+ all = subject.all.sort_by{ |pact_publication| pact_publication.consumer_version.order }
241
+ expect(all.size).to eq 2
242
+ expect(all.first.consumer.name).to eq "Foo"
243
+ expect(all.first.provider.name).to eq "Bar"
244
+ expect(all.first.consumer_version.number).to eq "2"
245
+
246
+ expect(all.last.consumer.name).to eq "Foo2"
247
+ expect(all.last.provider.name).to eq "Bar2"
248
+ expect(all.last.consumer_version.number).to eq "11"
249
+ end
250
+
251
+ it "does not return extra columns" do
252
+ expect(subject.all.first.values.keys.sort).to eq (PactPublication.columns + [:tag_name]).sort
253
+ end
254
+
255
+ context "when columns are already selected" do
256
+ subject { PactPublication.select(Sequel[:pact_publications][:id]).latest_for_consumer_tag("main") }
257
+
258
+ it "does not override them" do
259
+ expect(subject.all.first.values.keys).to eq [:id]
260
+ end
261
+ end
262
+
263
+ context "when chained" do
264
+ it "works" do
265
+ all = PactPublication.for_provider(td.find_pacticipant("Bar")).latest_for_consumer_tag("main").all
266
+ expect(all.first.provider.name).to eq "Bar"
267
+ end
268
+ end
269
+ end
270
+
271
+ describe "#successfully_verified_by_provider_branch" do
272
+ let(:bar) { td.find_pacticipant("Bar") }
273
+
274
+ subject { PactPublication.successfully_verified_by_provider_branch(bar.id, "main").all }
275
+
276
+ context "PactPublication" do
277
+ before do
278
+ td.create_pact_with_hierarchy("Foo", "1", "Bar")
279
+ .create_verification(provider_version: "2", branch: "main", success: false)
280
+ .create_pact_with_hierarchy("Foo", "2", "Bar")
281
+ .create_verification(provider_version: "2", branch: "main", success: true)
282
+ .create_pact_with_hierarchy("Foo", "3", "Bar")
283
+ .create_verification(provider_version: "3", branch: "not-main", success: true)
284
+ end
285
+
286
+ it "returns the pact publications that have been succesfully verified by the given provider id and branch" do
287
+ expect(subject.size).to eq 1
288
+ expect(subject.first.consumer_version.number).to eq "2"
289
+ end
290
+
291
+ it "does not return extra columns" do
292
+ expect(subject.first.values.keys.sort).to eq PactPublication.columns.sort
293
+ end
294
+ end
295
+
296
+
297
+ context "with chained scopes" do
298
+ subject { PactPublication.latest_by_consumer_branch.successfully_verified_by_provider_branch(bar.id, "provider-main").all }
299
+
300
+ context "when there are no latest branch pacts that have been successfully verified by the specified provider branch" do
301
+ before do
302
+ td.create_consumer("Foo")
303
+ .create_provider("Bar")
304
+ .create_consumer_version("1", branch: "main", comment: "not latest")
305
+ .create_pact
306
+ .create_verification(provider_version: "1", success: true, branch: "provider-main", comment: "successful but not latest")
307
+ .create_consumer_version("2", branch: "main", comment: "latest")
308
+ .create_pact
309
+ .create_verification(provider_version: "2", success: false, branch: "provider-main", comment: "latest but not successful")
310
+ .create_consumer_version("3", branch: "feat/x", comment: "latest")
311
+ .create_pact
312
+ .create_verification(provider_version: "3", success: true, branch: "not-provider-main", comment: "latest, successful, but wrong branch")
313
+ end
314
+
315
+ it { is_expected.to eq [] }
316
+ end
317
+
318
+ context "when there are latest branch pacts that have been successfully verified by the specified provider branch" do
319
+ before do
320
+ td.create_consumer("Foo")
321
+ .create_provider("Bar")
322
+ .create_consumer_version("1", branch: "main", comment: "not latest")
323
+ .create_pact
324
+ .create_verification(provider_version: "1", success: true, branch: "provider-main")
325
+ .create_consumer_version("2", branch: "main", comment: "latest")
326
+ .create_pact
327
+ .create_verification(provider_version: "1", success: true, branch: "provider-main")
328
+ .create_verification(provider_version: "2", success: true, branch: "provider-main", number: "2")
329
+ end
330
+
331
+ its(:size) { is_expected.to eq 1 }
332
+
333
+ it "returns them" do
334
+ expect(subject.first.consumer_version.number).to eq "2"
335
+ end
336
+ end
337
+
338
+ context "when there are latest tagged pacts that have been successfully verified by the specified provider branch" do
339
+ before do
340
+ td.create_consumer("Foo")
341
+ .create_provider("Bar")
342
+ .create_consumer_version("1", tag_names: ["main"], comment: "not latest")
343
+ .create_pact
344
+ .create_verification(provider_version: "1", success: true, tag_names: ["provider-main"])
345
+ .create_consumer_version("2", tag_names: ["main"], comment: "latest")
346
+ .create_pact
347
+ .create_verification(provider_version: "1", success: true, branch: "provider-main")
348
+ .create_verification(provider_version: "2", success: true, branch: "provider-main", number: "2")
349
+ end
350
+
351
+ subject { PactPublication.latest_by_consumer_tag.successfully_verified_by_provider_branch(bar.id, "provider-main").all }
352
+
353
+ its(:size) { is_expected.to eq 1 }
354
+
355
+ it "returns them" do
356
+ expect(subject.first.consumer_version.number).to eq "2"
357
+ end
358
+ end
359
+
360
+ context "subtracting Pact Publications" do
361
+ before do
362
+ td.create_consumer("Foo")
363
+ .create_provider("Bar")
364
+ .create_consumer_version("1", branch: "main", tag_names: ["main"], comment: "not latest")
365
+ .create_pact
366
+ .create_verification(provider_version: "1", success: true, branch: "provider-main")
367
+ .create_consumer_version("2", branch: "main", tag_names: ["main"], comment: "latest")
368
+ .create_pact
369
+ .create_verification(provider_version: "1", success: true, branch: "provider-main")
370
+ .create_verification(provider_version: "2", success: true, branch: "provider-main", number: "2")
371
+ .create_consumer_version("3", branch: "feat/x", tag_names: ["feat/x"], )
372
+ .create_pact
373
+ end
374
+
375
+ let(:bar) { td.find_pacticipant("Bar") }
376
+
377
+ it "with branches" do
378
+ potential = PactPublication.for_provider(bar).latest_by_consumer_branch
379
+ already_verified = potential.successfully_verified_by_provider_branch(bar.id, "provider-main")
380
+ not_verified = PactPublication.subtract(potential.all, already_verified.all)
381
+
382
+ expect(not_verified.size).to eq 1
383
+ expect(not_verified.first.consumer_version_number).to eq "3"
384
+ end
385
+
386
+ it "with tags" do
387
+ potential = PactPublication.for_provider(bar).latest_by_consumer_tag
388
+ already_verified = potential.successfully_verified_by_provider_branch(bar.id, "provider-main")
389
+ not_verified = PactPublication.subtract(potential.all, already_verified.all)
390
+
391
+ expect(not_verified.size).to eq 1
392
+ expect(not_verified.first.consumer_version_number).to eq "3"
393
+ end
394
+ end
395
+ end
396
+ end
397
+ end
398
+ end
399
+ end
400
+