pact_broker 2.91.0 → 2.93.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -0
  3. data/db/migrations/20210608_add_uuid_to_webhook.rb +1 -0
  4. data/db/migrations/20211120_create_pact_version_provider_tag_successful_verifications.rb +23 -0
  5. data/db/migrations/20211121_migrate_pact_version_provider_tag_successful_verifications_data.rb +11 -0
  6. data/lib/pact_broker/api/resources/deployed_versions_for_version_and_environment.rb +2 -2
  7. data/lib/pact_broker/api/resources/released_versions_for_version_and_environment.rb +5 -1
  8. data/lib/pact_broker/api/resources/verifications.rb +1 -1
  9. data/lib/pact_broker/config/runtime_configuration_database_methods.rb +6 -0
  10. data/lib/pact_broker/db/clean_incremental.rb +26 -9
  11. data/lib/pact_broker/db/data_migrations/migrate_pact_version_provider_tag_successful_verifications.rb +38 -0
  12. data/lib/pact_broker/db/migrate_data.rb +1 -0
  13. data/lib/pact_broker/deployments/deployed_version.rb +9 -1
  14. data/lib/pact_broker/domain/pacticipant.rb +36 -6
  15. data/lib/pact_broker/initializers/database_connection.rb +6 -4
  16. data/lib/pact_broker/metrics/service.rb +1 -1
  17. data/lib/pact_broker/pacts/pact_publication_dataset_module.rb +42 -43
  18. data/lib/pact_broker/pacts/pact_publication_wip_dataset_module.rb +37 -4
  19. data/lib/pact_broker/pacts/pacts_for_verification_repository.rb +1 -1
  20. data/lib/pact_broker/pacts/service.rb +3 -3
  21. data/lib/pact_broker/pacts/sort_content.rb +1 -1
  22. data/lib/pact_broker/test/http_test_data_builder.rb +1 -0
  23. data/lib/pact_broker/test/test_data_builder.rb +36 -9
  24. data/lib/pact_broker/verifications/pact_version_provider_tag_successful_verification.rb +11 -0
  25. data/lib/pact_broker/verifications/repository.rb +16 -0
  26. data/lib/pact_broker/version.rb +1 -1
  27. metadata +7 -4
  28. data/lib/pact_broker/versions/latest_version.rb +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1634d0a3519aae8c805e0c8f13e2e132e86b623c92e019d37285b98ecd7574d
4
- data.tar.gz: 2652bd80a29b04e222bad6ffb0513c95618f16185feb98cffc9c7bd283858b79
3
+ metadata.gz: 6014e4f21b22b1055f87d7f937b7d7942cb62f1ab7e6501299c8787e83986e22
4
+ data.tar.gz: 58b9668d0f34631533a507bce423d80fd0a1a8e2f98c04838a69ac83dc290f18
5
5
  SHA512:
6
- metadata.gz: 8e3bc701ea3fe67d6ffe24330faf61b5def23d7293e2c59bfa1d4c5b8874dd3ef8b622f8adbef202bdfd784804f67a5c9efd39c79c1bba54bb52a8fe2abc7661
7
- data.tar.gz: ab7a4c68f71251bbf36e3f58bb18267b28cc1bd72df5f3959caedd8fe1b776439b6ba25fd972f2a819ba5f0872d9861d22284da501a5d921f255aea368bedfab
6
+ metadata.gz: f26bd4ebafd8e30a3b8d96c2eb7c2ed5f594ef8cdfb477b89260169db34b77a32f01605b74f0a75e7f118eea1f8364e0c4f3e8d93df76617b041b526a3ff99e5
7
+ data.tar.gz: 807f0c5055108dfd8b8057a64580943dc6b1aeedb669156c1dcdad09cd4926ca8d6616646af62721f12ec2ab285a9cd9556d2821fc35177c7d04768a85c66347
data/CHANGELOG.md CHANGED
@@ -1,3 +1,45 @@
1
+ <a name="v2.93.2"></a>
2
+ ### v2.93.2 (2021-12-23)
3
+
4
+ #### Bug Fixes
5
+
6
+ * Improve SortContent performance on large contracts (#538) ([1914c01f](/../../commit/1914c01f))
7
+
8
+ <a name="v2.93.1"></a>
9
+ ### v2.93.1 (2021-12-21)
10
+
11
+ #### Bug Fixes
12
+
13
+ * optimise query for calculating the latest overall pacts ([f44aaa70](/../../commit/f44aaa70))
14
+
15
+ <a name="v2.93.0"></a>
16
+ ### v2.93.0 (2021-12-07)
17
+
18
+ #### Features
19
+
20
+ * remove feature flag for new_wip_calculations ([972ceadd](/../../commit/972ceadd))
21
+ * call the database clean within a transaction ([408c84ef](/../../commit/408c84ef))
22
+
23
+ #### Bug Fixes
24
+
25
+ * fix clean performance fix (#530) ([6c71e57b](/../../commit/6c71e57b))
26
+ * fix performance issue loading latest version for pacticipant ([c575d132](/../../commit/c575d132))
27
+
28
+ <a name="v2.92.0"></a>
29
+ ### v2.92.0 (2021-11-27)
30
+
31
+ #### Features
32
+
33
+ * allow SQL caller logging to be enabled ([861d8f21](/../../commit/861d8f21))
34
+ * use a separate table to track the successful verifications of pact versions for each provider version tag (feature toggled with "new_wip_calculation") ([df0acfa3](/../../commit/df0acfa3))
35
+
36
+ #### Bug Fixes
37
+
38
+ * **cleanup**
39
+ * Improve delete orphans SQL query (#527) ([853354ea](/../../commit/853354ea))
40
+
41
+ * cast PACT_BROKER_DATABASE_CONNECTION_VALIDATION_TIMEOUT to an integer ([8816c61f](/../../commit/8816c61f))
42
+
1
43
  <a name="v2.91.0"></a>
2
44
  ### v2.91.0 (2021-11-15)
3
45
 
@@ -8,6 +8,7 @@ Sequel.migration do
8
8
 
9
9
  down do
10
10
  alter_table(:triggered_webhooks) do
11
+ drop_index([:uuid], name: "triggered_webhooks_uuid", unique: true)
11
12
  drop_column(:uuid)
12
13
  end
13
14
  end
@@ -0,0 +1,23 @@
1
+ Sequel.migration do
2
+ up do
3
+ create_table(:pact_version_provider_tag_successful_verifications, charset: "utf8") do
4
+ primary_key :id
5
+ foreign_key :pact_version_id, :pact_versions, null: false, on_delete: :cascade, foreign_key_constraint_name: "pact_version_provider_tag_successful_verifications_pv_id_fk"
6
+ String :provider_version_tag_name, null: false
7
+ Boolean :wip, null: false
8
+ Integer :verification_id
9
+ DateTime :execution_date, null: false
10
+ index([:pact_version_id, :provider_version_tag_name, :wip], unique: true, name: "pact_version_provider_tag_verifications_pv_pvtn_wip_unique")
11
+ # The implication of the on_delete: :set_null for verification_id is
12
+ # that even if the verification result is deleted from the broker,
13
+ # the wip/pending status stays the same.
14
+ # We may or may not want this. Will have to wait and see.
15
+ # Have made the foreign key a separate declaration so it can more easily be remade.
16
+ foreign_key([:verification_id], :verifications, on_delete: :set_null, name: "pact_version_provider_tag_successful_verifications_v_id_fk")
17
+ end
18
+ end
19
+
20
+ down do
21
+ drop_table(:pact_version_provider_tag_successful_verifications)
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ require "pact_broker/db/data_migrations/migrate_pact_version_provider_tag_successful_verifications"
2
+
3
+ Sequel.migration do
4
+ up do
5
+ PactBroker::DB::DataMigrations::MigratePactVersionProviderTagSuccessfulVerifications.call(self)
6
+ end
7
+
8
+ down do
9
+
10
+ end
11
+ end
@@ -40,11 +40,11 @@ module PactBroker
40
40
  end
41
41
 
42
42
  def policy_name
43
- :'versions::version'
43
+ :'versions::deployed_version'
44
44
  end
45
45
 
46
46
  def policy_record
47
- version
47
+ environment
48
48
  end
49
49
 
50
50
  private
@@ -45,7 +45,11 @@ module PactBroker
45
45
  end
46
46
 
47
47
  def policy_name
48
- :'versions::versions'
48
+ :'versions::released_version'
49
+ end
50
+
51
+ def policy_record
52
+ environment
49
53
  end
50
54
 
51
55
  def finish_request
@@ -50,7 +50,7 @@ module PactBroker
50
50
  end
51
51
 
52
52
  def from_json
53
- handle_webhook_events do
53
+ handle_webhook_events(build_url: verification_params["buildUrl"]) do
54
54
  verified_pacts = pact_service.find_for_verification_publication(pact_params, event_context[:consumer_version_selectors])
55
55
  verification = verification_service.create(next_verification_number, verification_params, verified_pacts, event_context)
56
56
  response.body = decorator_for(verification).to_json(decorator_options)
@@ -18,6 +18,7 @@ module PactBroker
18
18
  database_sslmode: nil,
19
19
  sql_log_level: :debug,
20
20
  sql_log_warn_duration: 5,
21
+ sql_enable_caller_logging: false,
21
22
  database_max_connections: nil,
22
23
  database_pool_timeout: 5,
23
24
  database_connect_max_retries: 0,
@@ -36,6 +37,7 @@ module PactBroker
36
37
  encoding: "utf8",
37
38
  sslmode: database_sslmode,
38
39
  sql_log_level: sql_log_level,
40
+ enable_caller_logging: sql_enable_caller_logging,
39
41
  log_warn_duration: sql_log_warn_duration,
40
42
  max_connections: database_max_connections,
41
43
  pool_timeout: database_pool_timeout,
@@ -65,6 +67,10 @@ module PactBroker
65
67
  super(metrics_sql_statement_timeout&.to_i)
66
68
  end
67
69
 
70
+ def database_connection_validation_timeout= database_connection_validation_timeout
71
+ super(database_connection_validation_timeout&.to_i)
72
+ end
73
+
68
74
  def postgres?
69
75
  database_credentials[:adapter] == "postgres"
70
76
  end
@@ -66,13 +66,15 @@ module PactBroker
66
66
  if dry_run?
67
67
  dry_run_results
68
68
  else
69
- before_counts = current_counts
70
- PactBroker::Domain::Version.where(id: resolve_ids(version_ids_to_delete)).delete
71
- delete_orphan_pact_versions
72
- after_counts = current_counts
73
-
74
- TABLES.each_with_object({}) do | table_name, comparison_counts |
75
- comparison_counts[table_name.to_s] = { "deleted" => before_counts[table_name] - after_counts[table_name], "kept" => after_counts[table_name] }
69
+ db.transaction do
70
+ before_counts = current_counts
71
+ PactBroker::Domain::Version.where(id: resolve_ids(version_ids_to_delete)).delete
72
+ delete_orphan_pact_versions
73
+ after_counts = current_counts
74
+
75
+ TABLES.each_with_object({}) do | table_name, comparison_counts |
76
+ comparison_counts[table_name.to_s] = { "deleted" => before_counts[table_name] - after_counts[table_name], "kept" => after_counts[table_name] }
77
+ end
76
78
  end
77
79
  end
78
80
  end
@@ -92,8 +94,23 @@ module PactBroker
92
94
  end
93
95
 
94
96
  def delete_orphan_pact_versions
95
- referenced_pact_version_ids = db[:pact_publications].select(:pact_version_id).union(db[:verifications].select(:pact_version_id))
96
- db[:pact_versions].where(id: referenced_pact_version_ids).invert.delete
97
+ db[:pact_versions].where(id: orphan_pact_versions).delete
98
+ rescue Sequel::DatabaseError => e
99
+ raise unless e.cause.class.name == "Mysql2::Error"
100
+
101
+ ids = orphan_pact_versions.map { |row| row[:id] }
102
+ db[:pact_versions].where(id: ids).delete
103
+ end
104
+
105
+ def orphan_pact_versions
106
+ db[:pact_versions]
107
+ .left_join(:pact_publications, Sequel[:pact_publications][:pact_version_id]=> Sequel[:pact_versions][:id])
108
+ .left_join(:verifications, Sequel[:verifications][:pact_version_id]=> Sequel[:pact_versions][:id])
109
+ .select(Sequel[:pact_versions][:id])
110
+ .where(
111
+ Sequel[:pact_publications][:id] => nil,
112
+ Sequel[:verifications][:id] => nil
113
+ )
97
114
  end
98
115
 
99
116
  def version_info(version)
@@ -0,0 +1,38 @@
1
+ require "pact_broker/db/data_migrations/helpers"
2
+
3
+ module PactBroker
4
+ module DB
5
+ module DataMigrations
6
+ class MigratePactVersionProviderTagSuccessfulVerifications
7
+ extend Helpers
8
+
9
+ def self.call(connection)
10
+ successful_verifications_join = {
11
+ Sequel[:sv][:pact_version_id] => Sequel[:verifications][:pact_version_id],
12
+ Sequel[:sv][:provider_version_tag_name] => Sequel[:tags][:name],
13
+ Sequel[:sv][:wip] => Sequel[:verifications][:wip]
14
+ }
15
+
16
+ missing_verifications = connection
17
+ .select(
18
+ Sequel[:verifications][:pact_version_id],
19
+ Sequel[:tags][:name],
20
+ Sequel[:verifications][:wip],
21
+ Sequel[:verifications][:id],
22
+ Sequel[:verifications][:execution_date]
23
+ )
24
+ .order(Sequel[:verifications][:execution_date], Sequel[:verifications][:id])
25
+ .from(:verifications)
26
+ .join(:tags, { Sequel[:verifications][:provider_version_id] => Sequel[:tags][:version_id] })
27
+ .left_outer_join(:pact_version_provider_tag_successful_verifications, successful_verifications_join, { table_alias: :sv })
28
+ .where(Sequel[:sv][:pact_version_id] => nil)
29
+ .where(Sequel[:verifications][:success] => true)
30
+
31
+ connection[:pact_version_provider_tag_successful_verifications]
32
+ .insert_ignore
33
+ .insert([:pact_version_id, :provider_version_tag_name, :wip, :verification_id, :execution_date], missing_verifications)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -28,6 +28,7 @@ module PactBroker
28
28
  DataMigrations::SetExtraColumnsForTags.call(database_connection)
29
29
  DataMigrations::CreateBranches.call(database_connection)
30
30
  DataMigrations::MigrateIntegrations.call(database_connection)
31
+ DataMigrations::MigratePactVersionProviderTagSuccessfulVerifications.call(database_connection)
31
32
  end
32
33
  end
33
34
  end
@@ -88,6 +88,15 @@ module PactBroker
88
88
  !!currently_deployed_version_id
89
89
  end
90
90
 
91
+ # target has been renamed to applicationInstance in the API.
92
+ def application_instance
93
+ target
94
+ end
95
+
96
+ def application_instance= application_instance
97
+ self.target = application_instance
98
+ end
99
+
91
100
  def version_number
92
101
  version.number
93
102
  end
@@ -100,7 +109,6 @@ module PactBroker
100
109
  self.class.where(id: id).record_undeployed
101
110
  self.refresh
102
111
  end
103
-
104
112
  end
105
113
  end
106
114
  end
@@ -1,14 +1,44 @@
1
1
  require "pact_broker/db"
2
2
  require "pact_broker/messages"
3
3
  require "pact_broker/repositories/helpers"
4
- require "pact_broker/versions/latest_version"
5
4
  require "pact_broker/domain/label"
6
5
  require "pact_broker/string_refinements"
7
6
  require "pact_broker/pacticipants/generate_display_name"
8
7
 
9
8
  module PactBroker
10
9
  module Domain
10
+ class LatestVersionForPacticipantEagerLoader
11
+ def self.call(eo, **_other)
12
+ populate_associations(eo[:rows])
13
+ end
14
+
15
+ def self.populate_associations(pacticipants)
16
+ pacticipants.each { | pacticipant | pacticipant.associations[:latest_version] = nil }
17
+ pacticipant_ids = pacticipants.collect(&:id)
18
+
19
+ max_orders = PactBroker::Domain::Version
20
+ .where(pacticipant_id: pacticipant_ids)
21
+ .select_group(:pacticipant_id)
22
+ .select_append { max(order).as(latest_order) }
23
+
24
+ max_orders_join = {
25
+ Sequel[:max_orders][:latest_order] => Sequel[:versions][:order],
26
+ Sequel[:max_orders][:pacticipant_id] => Sequel[:versions][:pacticipant_id]
27
+ }
28
+
29
+ latest_versions = PactBroker::Domain::Version
30
+ .select_all_qualified
31
+ .join(max_orders, max_orders_join, { table_alias: :max_orders})
32
+
33
+ latest_versions.each do | version |
34
+ pacticipant = pacticipants.find{ | p | p.id == version.pacticipant_id }
35
+ pacticipant.associations[:latest_version] = version
36
+ end
37
+ end
38
+ end
39
+
11
40
  class Pacticipant < Sequel::Model
41
+
12
42
  include Messages
13
43
  include PactBroker::Pacticipants::GenerateDisplayName
14
44
  using PactBroker::StringRefinements
@@ -21,7 +51,11 @@ module PactBroker
21
51
  one_to_many :versions, :order => :order, :reciprocal => :pacticipant
22
52
  one_to_many :labels, :order => :name, :reciprocal => :pacticipant
23
53
  one_to_many :pacts
24
- one_to_one :latest_version, :class => "PactBroker::Versions::LatestVersion", primary_key: :id, key: :pacticipant_id
54
+ one_to_one :latest_version, :class => "PactBroker::Domain::Version",
55
+ primary_key: :id, key: :pacticipant_id,
56
+ dataset: lambda { PactBroker::Domain::Version.where(pacticipant_id: id).order(Sequel.desc(:order)).limit(1) },
57
+ eager_loader: LatestVersionForPacticipantEagerLoader
58
+
25
59
  one_to_many :branch_heads, class: "PactBroker::Versions::BranchHead", primary_key: :id, key: :pacticipant_id
26
60
  one_to_many :branches, class: "PactBroker::Versions::Branch", primary_key: :id, key: :pacticipant_id
27
61
 
@@ -61,10 +95,6 @@ module PactBroker
61
95
  self.main_branch = nil if main_branch.blank?
62
96
  end
63
97
 
64
- def latest_version
65
- versions.last
66
- end
67
-
68
98
  def to_s
69
99
  "Pacticipant: id=#{id}, name=#{name}"
70
100
  end
@@ -9,7 +9,8 @@ module PactBroker
9
9
  sequel_config = config.dup
10
10
  max_retries = sequel_config.delete(:connect_max_retries) || 0
11
11
  connection_validation_timeout = config.delete(:connection_validation_timeout)
12
- configure_logger(sequel_config)
12
+ enable_caller_logging = config.delete(:enable_caller_logging)
13
+ configure_logger(sequel_config, logger)
13
14
  create_sqlite_database_dir(config)
14
15
 
15
16
  connection = with_retries(max_retries, logger) do
@@ -18,7 +19,7 @@ module PactBroker
18
19
 
19
20
  logger&.info "Connected to database #{sequel_config[:database]}"
20
21
 
21
- configure_connection(connection, connection_validation_timeout)
22
+ configure_connection(connection, connection_validation_timeout, enable_caller_logging)
22
23
  end
23
24
 
24
25
  private_class_method def self.with_retries(max_retries, logger)
@@ -46,7 +47,7 @@ module PactBroker
46
47
  end
47
48
  end
48
49
 
49
- private_class_method def self.configure_logger(sequel_config)
50
+ private_class_method def self.configure_logger(sequel_config, logger)
50
51
  if sequel_config[:sql_log_level] == :none
51
52
  sequel_config.delete(:sql_log_level)
52
53
  elsif logger
@@ -72,8 +73,9 @@ module PactBroker
72
73
  # when databases are restarted and connections are killed. This has a performance
73
74
  # penalty, so consider increasing this timeout if building a frequently accessed service.
74
75
 
75
- private_class_method def self.configure_connection(connection, connection_validation_timeout)
76
+ private_class_method def self.configure_connection(connection, connection_validation_timeout, enable_caller_logging)
76
77
  connection.extension(:connection_validator)
78
+ connection.extension(:caller_logging) if enable_caller_logging
77
79
  connection.pool.connection_validation_timeout = connection_validation_timeout if connection_validation_timeout
78
80
  connection
79
81
  end
@@ -18,7 +18,7 @@ module PactBroker
18
18
  withMainBranchSetCount: PactBroker::Domain::Pacticipant.with_main_branch_set.count
19
19
  },
20
20
  integrations: {
21
- count: PactBroker::Integrations::Integration.count
21
+ count: PactBroker::Pacts::PactPublication.select(:consumer_id, :provider_id).distinct.count
22
22
  },
23
23
  pactPublications: {
24
24
  count: PactBroker::Pacts::PactPublication.count,
@@ -90,16 +90,18 @@ module PactBroker
90
90
  def overall_latest
91
91
  self_join = {
92
92
  Sequel[:pact_publications][:consumer_id] => Sequel[:pp2][:consumer_id],
93
- Sequel[:pact_publications][:provider_id] => Sequel[:pp2][:provider_id]
93
+ Sequel[:pact_publications][:provider_id] => Sequel[:pp2][:provider_id],
94
+ Sequel[:pact_publications][:consumer_version_order] => Sequel[:pp2][:max_consumer_version_order]
94
95
  }
95
96
 
96
97
  base_query = self
97
98
  base_query = base_query.select_all_qualified if no_columns_selected?
98
99
 
99
- base_query.left_join(base_query.select(:consumer_id, :provider_id, :consumer_version_order), self_join, { table_alias: :pp2 } ) do
100
- Sequel[:pp2][:consumer_version_order] > Sequel[:pact_publications][:consumer_version_order]
101
- end
102
- .where(Sequel[:pp2][:consumer_version_order] => nil)
100
+ base_query.join(
101
+ base_query.select_group(:consumer_id, :provider_id).select_append{ max(:consumer_version_order).as(:max_consumer_version_order) },
102
+ self_join,
103
+ table_alias: :pp2
104
+ )
103
105
  .remove_overridden_revisions_from_complete_query
104
106
  end
105
107
 
@@ -140,65 +142,62 @@ module PactBroker
140
142
  end
141
143
 
142
144
  # The latest pact publication for each tag
145
+ # This uses the old logic of "the latest pact for a version that has a tag" (which always returns a pact)
146
+ # rather than "the pact for the latest version with a tag"
147
+ # Need to see about updating this.
143
148
  def latest_by_consumer_tag
144
149
  tags_join = {
145
- Sequel[:pact_publications][:consumer_version_id] => Sequel[:tags][:version_id]
150
+ Sequel[:pact_publications][:consumer_version_id] => Sequel[:tags][:version_id],
146
151
  }
147
152
 
148
- base_query = join(:tags, tags_join)
153
+ max_orders = join(:tags, tags_join)
154
+ .select_group(:consumer_id, :provider_id, Sequel[:tags][:name].as(:tag_name))
155
+ .select_append{ max(consumer_version_order).as(latest_consumer_version_order) }
149
156
 
157
+ max_join = {
158
+ Sequel[:max_orders][:consumer_id] => Sequel[:pact_publications][:consumer_id],
159
+ Sequel[:max_orders][:provider_id] => Sequel[:pact_publications][:provider_id],
160
+ Sequel[:max_orders][:latest_consumer_version_order] => Sequel[:pact_publications][:consumer_version_order]
161
+ }
162
+
163
+ base_query = self
150
164
  if no_columns_selected?
151
- base_query = base_query.select_all_qualified.select_append(Sequel[:tags][:name].as(:tag_name))
165
+ base_query = base_query.select_all_qualified.select_append(Sequel[:max_orders][:tag_name])
152
166
  end
153
167
 
154
- joined_query = base_query.select(
155
- Sequel[:pact_publications][:consumer_id],
156
- Sequel[:tags][:version_order],
157
- Sequel[:tags][:name].as(:tag_name)
158
- )
159
-
160
- self_join = {
161
- Sequel[:pact_publications][:consumer_id] => Sequel[:pp2][:consumer_id],
162
- Sequel[:tags][:name] => Sequel[:pp2][:tag_name]
163
- }
164
- base_query.left_join(joined_query, self_join, { table_alias: :pp2 } ) do
165
- Sequel[:pp2][:version_order] > Sequel[:tags][:version_order]
166
- end
167
- .where(Sequel[:pp2][:version_order] => nil)
168
- .remove_overridden_revisions_from_complete_query
168
+ base_query
169
+ .join(max_orders, max_join, { table_alias: :max_orders })
170
+ .remove_overridden_revisions_from_complete_query
169
171
  end
170
172
 
173
+ # This uses the old logic of "the latest pact for a version that has a tag" (which always returns a pact)
174
+ # rather than "the pact for the latest version with a tag"
175
+ # Need to see about updating this.
171
176
  def latest_for_consumer_tag(tag_name)
172
177
  tags_join = {
173
178
  Sequel[:pact_publications][:consumer_version_id] => Sequel[:tags][:version_id],
174
179
  Sequel[:tags][:name] => tag_name
175
180
  }
176
181
 
177
- base_query = self
178
- if no_columns_selected?
179
- base_query = base_query.select_all_qualified.select_append(Sequel[:tags][:name].as(:tag_name))
180
- end
181
-
182
- base_query = base_query
183
- .join(:tags, tags_join)
184
- .where(Sequel[:tags][:name] => tag_name)
182
+ max_orders = join(:tags, tags_join)
183
+ .select_group(:consumer_id, :provider_id, Sequel[:tags][:name].as(:tag_name))
184
+ .select_append{ max(consumer_version_order).as(latest_consumer_version_order) }
185
185
 
186
- joined_query = base_query.select(
187
- Sequel[:pact_publications][:consumer_id],
188
- Sequel[:tags][:name].as(:tag_name),
189
- Sequel[:tags][:version_order]
190
- )
191
186
 
192
- self_join = {
193
- Sequel[:pact_publications][:consumer_id] => Sequel[:pp2][:consumer_id],
194
- Sequel[:tags][:name] => Sequel[:pp2][:tag_name]
187
+ max_join = {
188
+ Sequel[:max_orders][:consumer_id] => Sequel[:pact_publications][:consumer_id],
189
+ Sequel[:max_orders][:provider_id] => Sequel[:pact_publications][:provider_id],
190
+ Sequel[:max_orders][:latest_consumer_version_order] => Sequel[:pact_publications][:consumer_version_order]
195
191
  }
196
192
 
197
- base_query.left_join(joined_query, self_join, { table_alias: :pp2 } ) do
198
- Sequel[:pp2][:version_order] > Sequel[:tags][:version_order]
193
+ base_query = self
194
+ if no_columns_selected?
195
+ base_query = base_query.select_all_qualified.select_append(Sequel[:max_orders][:tag_name])
199
196
  end
200
- .where(Sequel[:pp2][:version_order] => nil)
201
- .remove_overridden_revisions_from_complete_query
197
+
198
+ base_query
199
+ .join(max_orders, max_join, { table_alias: :max_orders })
200
+ .remove_overridden_revisions_from_complete_query
202
201
  end
203
202
 
204
203
  # The pacts for the latest versions with the specified tag (new logic)
@@ -32,16 +32,23 @@ module PactBroker
32
32
  end
33
33
  end
34
34
 
35
- def successfully_verified_by_provider_tag_when_not_wip(provider_id, provider_tag)
35
+ def successfully_verified_by_provider_tag_when_not_wip(provider_tag)
36
+ pact_version_provider_tag_verifications_join = {
37
+ Sequel[:sv][:pact_version_id] => Sequel[:pp][:pact_version_id],
38
+ Sequel[:sv][:provider_version_tag_name] => provider_tag,
39
+ Sequel[:sv][:wip] => false
40
+ }
41
+
36
42
  from_self(alias: :pp)
37
43
  .select(Sequel[:pp].*)
38
- .where(Sequel[:pp][:provider_id] => provider_id)
39
- .join_successful_non_wip_verifications_for_provider_id(provider_id)
40
- .join_provider_version_tags_for_tag(provider_tag)
44
+ .join(:pact_version_provider_tag_successful_verifications, pact_version_provider_tag_verifications_join, { table_alias: :sv })
41
45
  .distinct
46
+
42
47
  end
43
48
 
44
49
  def successfully_verified_by_provider_another_tag_before_this_tag_first_created(provider_id, provider_tag)
50
+ return new_successfully_verified_by_provider_another_tag_before_this_tag_first_created(provider_id, provider_tag) if PactBroker.feature_enabled?(:new_wip_calculation)
51
+
45
52
  first_tag_with_name = PactBroker::Domain::Tag.where(pacticipant_id: provider_id, name: provider_tag).order(:created_at).first
46
53
  from_self(alias: :pp)
47
54
  .select(Sequel[:pp].*)
@@ -54,6 +61,32 @@ module PactBroker
54
61
  .distinct
55
62
  end
56
63
 
64
+ def new_successfully_verified_by_provider_another_tag_before_this_tag_first_created(provider_id, provider_tag)
65
+ first_tag_with_name = PactBroker::Domain::Tag.where(pacticipant_id: provider_id, name: provider_tag).order(:created_at).first
66
+
67
+ pact_version_provider_tag_verifications_join = {
68
+ Sequel[:sv][:pact_version_id] => Sequel[:pp][:pact_version_id],
69
+ Sequel[:sv][:wip] => false
70
+ }
71
+
72
+ created_at_criteria = if first_tag_with_name
73
+ Sequel.lit("sv.execution_date < ?", first_tag_with_name.created_at)
74
+ else
75
+ Sequel.lit("1 = 1")
76
+ end
77
+
78
+ from_self(alias: :pp)
79
+ .select(Sequel[:pp].*)
80
+ .where(Sequel[:pp][:provider_id] => provider_id)
81
+ .join(:pact_version_provider_tag_successful_verifications, pact_version_provider_tag_verifications_join, { table_alias: :sv }) do
82
+ Sequel.&(
83
+ Sequel.lit("sv.provider_version_tag_name NOT IN (?)", provider_tag),
84
+ created_at_criteria
85
+ )
86
+ end
87
+ .distinct
88
+ end
89
+
57
90
  protected
58
91
 
59
92
  def verified_before_date(date)
@@ -270,7 +270,7 @@ module PactBroker
270
270
 
271
271
  def remove_non_wip_for_tag(pact_publications_query, provider, tag, specified_pact_version_shas)
272
272
  specified_explicitly = pact_publications_query.for_pact_version_sha(specified_pact_version_shas)
273
- verified_by_this_tag = pact_publications_query.successfully_verified_by_provider_tag_when_not_wip(provider.id, tag)
273
+ verified_by_this_tag = pact_publications_query.successfully_verified_by_provider_tag_when_not_wip(tag)
274
274
  verified_by_another_tag = pact_publications_query.successfully_verified_by_provider_another_tag_before_this_tag_first_created(provider.id, tag)
275
275
 
276
276
  log_debug_for_wip do
@@ -43,7 +43,7 @@ module PactBroker
43
43
  end
44
44
 
45
45
  def delete params
46
- logger.info "Deleting pact version with params #{params}"
46
+ logger.info "Deleting pact version", payload: params
47
47
  pacts = pact_repository.find_all_revisions(params[:consumer_name], params[:consumer_version_number], params[:provider_name])
48
48
  webhook_service.delete_all_webhook_related_objects_by_pact_publication_ids(pacts.collect(&:id))
49
49
  pact_repository.delete(params)
@@ -156,7 +156,7 @@ module PactBroker
156
156
 
157
157
  # Overwriting an existing pact with the same consumer/provider/consumer version number
158
158
  def create_pact_revision params, existing_pact
159
- logger.info "Updating existing pact publication", payload: params.reject{ |k, _v| k == :json_content }
159
+ logger.info "Updating existing pact publication", payload: params.without(:json_content)
160
160
  logger.debug "Content #{params[:json_content]}"
161
161
  pact_version_sha = generate_sha(params[:json_content])
162
162
  json_content = add_interaction_ids(params[:json_content])
@@ -185,7 +185,7 @@ module PactBroker
185
185
 
186
186
  # When no publication for the given consumer/provider/consumer version number exists
187
187
  def create_pact params, version, provider
188
- logger.info "Creating new pact publication with params #{params.reject{ |k, _v| k == :json_content}}"
188
+ logger.info "Creating new pact publication", payload: params.without(:json_content)
189
189
  logger.debug "Content #{params[:json_content]}"
190
190
  pact_version_sha = generate_sha(params[:json_content])
191
191
  json_content = add_interaction_ids(params[:json_content])
@@ -34,7 +34,7 @@ module PactBroker
34
34
  # You never can tell what people will do...
35
35
  if probably_array.is_a?(Array)
36
36
  array_with_ordered_hashes = order_hash_keys(probably_array)
37
- array_with_ordered_hashes.sort{ |a, b| a.to_json <=> b.to_json }
37
+ array_with_ordered_hashes.sort_by(&:to_json)
38
38
  else
39
39
  probably_array
40
40
  end
@@ -273,6 +273,7 @@ module PactBroker
273
273
  "eventName" => "${pactbroker.eventName}",
274
274
  "consumerVersionNumber" => "${pactbroker.consumerVersionNumber}",
275
275
  "consumerVersionTags" => "${pactbroker.consumerVersionTags}",
276
+ "consumerVersionBranch" => "${pactbroker.consumerVersionBranch}",
276
277
  "githubVerificationStatus" => "${pactbroker.githubVerificationStatus}",
277
278
  "providerVersionNumber" => "${pactbroker.providerVersionNumber}",
278
279
  "providerVersionTags" => "${pactbroker.providerVersionTags}",
@@ -31,6 +31,8 @@ require "pact_broker/deployments/deployed_version_service"
31
31
  require "pact_broker/deployments/released_version_service"
32
32
  require "pact_broker/versions/branch_version_repository"
33
33
  require "pact_broker/integrations/repository"
34
+ require "pact_broker/contracts/service"
35
+
34
36
  require "ostruct"
35
37
 
36
38
  module PactBroker
@@ -219,6 +221,27 @@ module PactBroker
219
221
  self
220
222
  end
221
223
 
224
+ def publish_pact(consumer_name:, provider_name:, consumer_version_number: , tags: nil, branch: nil, build_url: nil, json_content: nil)
225
+ json_content = json_content || random_json_content(consumer_name, provider_name)
226
+ contracts = [
227
+ PactBroker::Contracts::ContractToPublish.from_hash(consumer_name: consumer_name, provider_name: provider_name, decoded_content: json_content, content_type: "application/json", specification: "pact")
228
+ ]
229
+ contracts_to_publish = PactBroker::Contracts::ContractsToPublish.from_hash(
230
+ pacticipant_name: consumer_name,
231
+ pacticipant_version_number: consumer_version_number,
232
+ tags: tags,
233
+ branch: branch,
234
+ build_url: build_url,
235
+ contracts: contracts
236
+ )
237
+ PactBroker::Contracts::Service.publish(contracts_to_publish, base_url: "http://example.org")
238
+ @consumer = find_pacticipant(consumer_name)
239
+ @consumer_version = find_version(consumer_name, consumer_version_number)
240
+ @provider = find_pacticipant(provider_name)
241
+ @pact = PactBroker::Pacts::PactPublication.last.to_domain
242
+ self
243
+ end
244
+
222
245
  def create_pact params = {}
223
246
  params.delete(:comment)
224
247
  json_content = params[:json_content] || default_json_content
@@ -363,6 +386,7 @@ module PactBroker
363
386
  end
364
387
 
365
388
  def create_verification parameters = {}
389
+ # This should use the verification service. what a mess
366
390
  parameters.delete(:comment)
367
391
  branch = parameters.delete(:branch)
368
392
  tag_names = [parameters.delete(:tag_names), parameters.delete(:tag_name)].flatten.compact
@@ -373,20 +397,23 @@ module PactBroker
373
397
  parameters.delete(:provider_version)
374
398
  verification = PactBroker::Domain::Verification.new(parameters)
375
399
  pact_version = PactBroker::Pacts::Repository.new.find_pact_version(@consumer, @provider, pact.pact_version_sha)
376
- @verification = PactBroker::Verifications::Repository.new.create(verification, provider_version_number, pact_version)
377
- @provider_version = PactBroker::Domain::Version.where(pacticipant_id: @provider.id, number: provider_version_number).single_record
400
+ @provider_version = version_repository.find_by_pacticipant_id_and_number_or_create(provider.id, provider_version_number)
378
401
  PactBroker::Versions::BranchVersionRepository.new.add_branch(@provider_version, branch) if branch
379
402
 
380
- set_created_at_if_set(parameters[:created_at], :verifications, id: @verification.id)
381
- set_created_at_if_set(parameters[:created_at], :versions, id: @provider_version.id)
382
- set_created_at_if_set(parameters[:created_at], :latest_verification_id_for_pact_version_and_provider_version, pact_version_id: pact_version_id, provider_version_id: @provider_version.id)
383
-
384
403
  if tag_names.any?
385
404
  tag_names.each do | tag_name |
386
- PactBroker::Domain::Tag.new(name: tag_name, version: @provider_version).insert_ignore
405
+ PactBroker::Domain::Tag.new(name: tag_name, version: @provider_version, version_order: @provider_version.order).insert_ignore
387
406
  set_created_at_if_set(parameters[:created_at], :tags, version_id: @provider_version.id, name: tag_name)
388
407
  end
389
408
  end
409
+
410
+ @verification = PactBroker::Verifications::Repository.new.create(verification, provider_version_number, pact_version)
411
+
412
+ set_created_at_if_set(parameters[:created_at], :verifications, id: @verification.id)
413
+ set_created_at_if_set(parameters[:created_at], :versions, id: @provider_version.id)
414
+ set_created_at_if_set(parameters[:created_at], :latest_verification_id_for_pact_version_and_provider_version, pact_version_id: pact_version_id, provider_version_id: @provider_version.id)
415
+ set_created_at_if_set(parameters[:created_at], :pact_version_provider_tag_successful_verifications, { verification_id: @verification.id }, :execution_date)
416
+
390
417
  self
391
418
  end
392
419
 
@@ -594,10 +621,10 @@ module PactBroker
594
621
  PactBroker::Pacts::Content.from_json(json_content).with_ids(false).to_json
595
622
  end
596
623
 
597
- def set_created_at_if_set created_at, table_name, selector
624
+ def set_created_at_if_set created_at, table_name, selector, date_column_name = :created_at
598
625
  date_to_set = created_at || @now
599
626
  if date_to_set
600
- Sequel::Model.db[table_name].where(selector).update(created_at: date_to_set)
627
+ Sequel::Model.db[table_name].where(selector).update(date_column_name => date_to_set)
601
628
  if Sequel::Model.db.schema(table_name).any?{ |col| col.first == :updated_at }
602
629
  Sequel::Model.db[table_name].where(selector.keys.first => selector.values.first).update(updated_at: date_to_set)
603
630
  end
@@ -0,0 +1,11 @@
1
+ require "pact_broker/domain/verification"
2
+
3
+ # Represents a non WIP, successful verification for a provider version with a tag.
4
+
5
+ module PactBroker
6
+ module Verifications
7
+ class PactVersionProviderTagSuccessfulVerification < Sequel::Model
8
+ plugin :insert_ignore, identifying_columns: [:pact_version_id, :provider_version_tag_name, :wip]
9
+ end
10
+ end
11
+ end
@@ -2,6 +2,7 @@ require "sequel"
2
2
  require "pact_broker/domain/verification"
3
3
  require "pact_broker/verifications/sequence"
4
4
  require "pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version"
5
+ require "pact_broker/verifications/pact_version_provider_tag_successful_verification"
5
6
 
6
7
  module PactBroker
7
8
  module Verifications
@@ -27,6 +28,7 @@ module PactBroker
27
28
  verification.tag_names = version.tag_names # TODO pass this in from contracts service
28
29
  verification.save
29
30
  update_latest_verification_id(verification)
31
+ update_pact_version_provider_tag_verifications(verification, version.tag_names)
30
32
  verification
31
33
  end
32
34
 
@@ -46,6 +48,20 @@ module PactBroker
46
48
  LatestVerificationIdForPactVersionAndProviderVersion.new(params).upsert
47
49
  end
48
50
 
51
+ def update_pact_version_provider_tag_verifications(verification, tag_names)
52
+ if verification.success
53
+ tag_names&.each do | tag_name |
54
+ PactVersionProviderTagSuccessfulVerification.new(
55
+ pact_version_id: verification.pact_version_id,
56
+ provider_version_tag_name: tag_name,
57
+ wip: verification.wip,
58
+ verification_id: verification.id,
59
+ execution_date: verification.execution_date
60
+ ).insert_ignore
61
+ end
62
+ end
63
+ end
64
+
49
65
  def find consumer_name, provider_name, pact_version_sha, verification_number
50
66
  PactBroker::Domain::Verification
51
67
  .select_all_qualified
@@ -1,3 +1,3 @@
1
1
  module PactBroker
2
- VERSION = "2.91.0"
2
+ VERSION = "2.93.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pact_broker
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.91.0
4
+ version: 2.93.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bethany Skurrie
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-11-15 00:00:00.000000000 Z
13
+ date: 2021-12-23 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: httparty
@@ -587,6 +587,8 @@ files:
587
587
  - db/migrations/20211102_create_table_temp_integrations.rb
588
588
  - db/migrations/20211103_migrate_integrations.rb
589
589
  - db/migrations/20211104_switch_integrations_and_temp_integrations.rb
590
+ - db/migrations/20211120_create_pact_version_provider_tag_successful_verifications.rb
591
+ - db/migrations/20211121_migrate_pact_version_provider_tag_successful_verifications_data.rb
590
592
  - db/migrations/migration_helper.rb
591
593
  - docs/CONFIGURATION.md
592
594
  - docs/api/WEBHOOKS.md
@@ -797,6 +799,7 @@ files:
797
799
  - lib/pact_broker/db/data_migrations/delete_deprecated_webhook_executions.rb
798
800
  - lib/pact_broker/db/data_migrations/helpers.rb
799
801
  - lib/pact_broker/db/data_migrations/migrate_integrations.rb
802
+ - lib/pact_broker/db/data_migrations/migrate_pact_version_provider_tag_successful_verifications.rb
800
803
  - lib/pact_broker/db/data_migrations/migrate_webhook_headers.rb
801
804
  - lib/pact_broker/db/data_migrations/set_consumer_ids_for_pact_publications.rb
802
805
  - lib/pact_broker/db/data_migrations/set_consumer_version_order_for_pact_publications.rb
@@ -1028,6 +1031,7 @@ files:
1028
1031
  - lib/pact_broker/verifications/latest_verification_for_consumer_and_provider.rb
1029
1032
  - lib/pact_broker/verifications/latest_verification_for_consumer_version_tag.rb
1030
1033
  - lib/pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version.rb
1034
+ - lib/pact_broker/verifications/pact_version_provider_tag_successful_verification.rb
1031
1035
  - lib/pact_broker/verifications/placeholder_verification.rb
1032
1036
  - lib/pact_broker/verifications/pseudo_branch_status.rb
1033
1037
  - lib/pact_broker/verifications/repository.rb
@@ -1043,7 +1047,6 @@ files:
1043
1047
  - lib/pact_broker/versions/branch_version.rb
1044
1048
  - lib/pact_broker/versions/branch_version_repository.rb
1045
1049
  - lib/pact_broker/versions/eager_loaders.rb
1046
- - lib/pact_broker/versions/latest_version.rb
1047
1050
  - lib/pact_broker/versions/parse_semantic_version.rb
1048
1051
  - lib/pact_broker/versions/repository.rb
1049
1052
  - lib/pact_broker/versions/selector.rb
@@ -1220,7 +1223,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1220
1223
  - !ruby/object:Gem::Version
1221
1224
  version: '0'
1222
1225
  requirements: []
1223
- rubygems_version: 3.2.31
1226
+ rubygems_version: 3.3.1
1224
1227
  signing_key:
1225
1228
  specification_version: 4
1226
1229
  summary: See description
@@ -1,21 +0,0 @@
1
- require "pact_broker/domain/version"
2
-
3
- module PactBroker
4
- module Versions
5
- include PactBroker::Repositories::Helpers
6
-
7
- class LatestVersion < PactBroker::Domain::Version
8
- set_dataset(:latest_versions)
9
- end
10
- end
11
- end
12
-
13
- # Table: latest_versions
14
- # Columns:
15
- # id | integer |
16
- # number | text |
17
- # repository_ref | text |
18
- # pacticipant_id | integer |
19
- # order | integer |
20
- # created_at | timestamp without time zone |
21
- # updated_at | timestamp without time zone |