pact_broker 2.91.0 → 2.93.2

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 (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 |