pact_broker 2.27.6 → 2.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/.travis.yml +1 -2
  4. data/CHANGELOG.md +38 -0
  5. data/MATRIX.md +4 -0
  6. data/README.md +3 -2
  7. data/Rakefile +1 -2
  8. data/config/database.yml +5 -0
  9. data/lib/pact_broker/api/decorators/matrix_decorator.rb +7 -1
  10. data/lib/pact_broker/api/decorators/reason_decorator.rb +50 -0
  11. data/lib/pact_broker/api/resources/base_resource.rb +1 -1
  12. data/lib/pact_broker/api/resources/error_handler.rb +32 -9
  13. data/lib/pact_broker/app.rb +16 -1
  14. data/lib/pact_broker/domain/webhook_request.rb +1 -1
  15. data/lib/pact_broker/matrix/deployment_status_summary.rb +123 -44
  16. data/lib/pact_broker/matrix/head_row.rb +20 -0
  17. data/lib/pact_broker/matrix/integration.rb +49 -7
  18. data/lib/pact_broker/matrix/query_results.rb +3 -2
  19. data/lib/pact_broker/matrix/query_results_with_deployment_status_summary.rb +2 -2
  20. data/lib/pact_broker/matrix/reason.rb +74 -0
  21. data/lib/pact_broker/matrix/repository.rb +97 -61
  22. data/lib/pact_broker/matrix/resolved_selector.rb +126 -0
  23. data/lib/pact_broker/matrix/row.rb +8 -1
  24. data/lib/pact_broker/matrix/service.rb +2 -16
  25. data/lib/pact_broker/pacts/repository.rb +15 -5
  26. data/lib/pact_broker/repositories/helpers.rb +3 -2
  27. data/lib/pact_broker/ui/views/index/_navbar.haml +14 -0
  28. data/lib/pact_broker/ui/views/index/show-with-tags.haml +1 -12
  29. data/lib/pact_broker/ui/views/index/show.haml +1 -12
  30. data/lib/pact_broker/ui/views/layouts/main.haml +3 -0
  31. data/lib/pact_broker/version.rb +1 -1
  32. data/lib/pact_broker/webhooks/job.rb +11 -5
  33. data/lib/pact_broker/webhooks/service.rb +10 -2
  34. data/lib/pact_broker/webhooks/webhook.rb +4 -0
  35. data/lib/rack/pact_broker/database_transaction.rb +22 -0
  36. data/pact_broker.gemspec +25 -1
  37. data/script/restart.sh +18 -0
  38. data/script/watch.sh +7 -0
  39. data/spec/features/publish_verification_spec.rb +1 -1
  40. data/spec/integration/app_spec.rb +1 -1
  41. data/spec/integration/webhooks/certificate_spec.rb +10 -2
  42. data/spec/lib/pact_broker/api/decorators/matrix_decorator_spec.rb +2 -1
  43. data/spec/lib/pact_broker/api/decorators/reason_decorator_spec.rb +59 -0
  44. data/spec/lib/pact_broker/api/resources/error_handler_spec.rb +84 -21
  45. data/spec/lib/pact_broker/app_spec.rb +22 -0
  46. data/spec/lib/pact_broker/domain/webhook_request_spec.rb +1 -1
  47. data/spec/lib/pact_broker/matrix/deployment_status_summary_spec.rb +116 -28
  48. data/spec/lib/pact_broker/matrix/head_row_spec.rb +23 -0
  49. data/spec/lib/pact_broker/matrix/integration_spec.rb +242 -0
  50. data/spec/lib/pact_broker/matrix/repository_dependency_spec.rb +58 -0
  51. data/spec/lib/pact_broker/matrix/repository_spec.rb +40 -7
  52. data/spec/lib/pact_broker/matrix/service_spec.rb +0 -50
  53. data/spec/lib/pact_broker/pacts/repository_spec.rb +20 -4
  54. data/spec/lib/pact_broker/webhooks/job_spec.rb +9 -9
  55. data/spec/lib/pact_broker/webhooks/service_spec.rb +3 -3
  56. data/spec/lib/pact_broker/webhooks/webhook_spec.rb +39 -0
  57. data/spec/lib/rack/pact_broker/database_transaction_spec.rb +40 -0
  58. data/spec/service_consumers/pact_helper.rb +2 -0
  59. data/spec/spec_helper.rb +2 -3
  60. data/spec/support/jobs.rb +12 -0
  61. data/spec/support/migration_helpers.rb +1 -1
  62. data/spec/support/simplecov.rb +10 -0
  63. data/tasks/audit.rake +2 -0
  64. data/tasks/pact.rake +5 -1
  65. data/tasks/rspec.rake +14 -0
  66. metadata +50 -5
  67. data/db/pact_broker_database.sqlite3 +0 -0
  68. data/spec/lib/pact_broker/matrix/repository_find_integrations_spec.rb +0 -51
@@ -1,4 +1,5 @@
1
1
  require 'pact_broker/matrix/row'
2
+ require 'pact_broker/webhooks/webhook'
2
3
 
3
4
  module PactBroker
4
5
  module Matrix
@@ -29,6 +30,25 @@ module PactBroker
29
30
  end
30
31
  end
31
32
  end)
33
+
34
+ # When viewing the index, every webhook in the database will match at least one of the rows, so
35
+ # it makes sense to load the entire table and match each webhook to the appropriate row.
36
+ # This will only work when using eager loading. The keys are just blanked out to avoid errors.
37
+ # I don't understand how they work at all.
38
+ # It would be nice to do this declaratively.
39
+ many_to_many :webhooks, :left_key => [], left_primary_key: [], :eager_loader=>(proc do |eo_opts|
40
+ eo_opts[:rows].each do |row|
41
+ row.associations[:webhooks] = []
42
+ end
43
+
44
+ PactBroker::Webhooks::Webhook.each do | webhook |
45
+ eo_opts[:rows].each do | row |
46
+ if webhook.is_for?(row)
47
+ row.associations[:webhooks] << webhook
48
+ end
49
+ end
50
+ end
51
+ end)
32
52
  end
33
53
  end
34
54
  end
@@ -1,17 +1,22 @@
1
- #
2
- # Represents the integration relationship between a consumer and a provider
3
- #
1
+
2
+ # Represents the integration relationship between a consumer and a provider in the context
3
+ # of a matrix or can-i-deploy query.
4
+ # If the required flag is set, then one of the pacticipants (consumers) specified in the HTTP query
5
+ # requires the provider. It would not be required if a provider was specified, and it had an
6
+ # integration with a consumer.
7
+
4
8
  module PactBroker
5
9
  module Matrix
6
10
  class Integration
7
11
 
8
12
  attr_reader :consumer_name, :consumer_id, :provider_name, :provider_id
9
13
 
10
- def initialize consumer_id, consumer_name, provider_id, provider_name
14
+ def initialize consumer_id, consumer_name, provider_id, provider_name, required
11
15
  @consumer_id = consumer_id
12
16
  @consumer_name = consumer_name
13
17
  @provider_id = provider_id
14
18
  @provider_name = provider_name
19
+ @required = required
15
20
  end
16
21
 
17
22
  def self.from_hash hash
@@ -19,10 +24,23 @@ module PactBroker
19
24
  hash.fetch(:consumer_id),
20
25
  hash.fetch(:consumer_name),
21
26
  hash.fetch(:provider_id),
22
- hash.fetch(:provider_name)
27
+ hash.fetch(:provider_name),
28
+ hash.fetch(:required)
23
29
  )
24
30
  end
25
31
 
32
+ def consumer
33
+ @consumer ||= OpenStruct.new(name: consumer_name, id: consumer_id)
34
+ end
35
+
36
+ def provider
37
+ @provider ||= OpenStruct.new(name: provider_name, id: provider_id)
38
+ end
39
+
40
+ def required?
41
+ @required
42
+ end
43
+
26
44
  def == other
27
45
  consumer_id == other.consumer_id && provider_id == other.provider_id
28
46
  end
@@ -30,7 +48,7 @@ module PactBroker
30
48
  def <=> other
31
49
  comparison = consumer_name <=> other.consumer_name
32
50
  return comparison if comparison != 0
33
- provider_name <=> other.provider_name
51
+ comparison =provider_name <=> other.provider_name
34
52
  end
35
53
 
36
54
  def to_hash
@@ -47,7 +65,31 @@ module PactBroker
47
65
  end
48
66
 
49
67
  def to_s
50
- "Relationship between #{consumer_name} (id=#{consumer_id}) and #{provider_name} (id=#{provider_id})"
68
+ "Integration between #{consumer_name} (id=#{consumer_id}) and #{provider_name} (id=#{provider_id})"
69
+ end
70
+
71
+ def involves_consumer_with_id?(consumer_id)
72
+ self.consumer_id == consumer_id
73
+ end
74
+
75
+ def involves_consumer_with_names?(consumer_names)
76
+ consumer_names.include?(self.consumer_name)
77
+ end
78
+
79
+ def involves_provider_with_name?(provider_name)
80
+ self.provider_name == provider_name
81
+ end
82
+
83
+ def involves_consumer_with_name?(consumer_name)
84
+ self.consumer_name == consumer_name
85
+ end
86
+
87
+ def pacticipant_names
88
+ [consumer_name, provider_name]
89
+ end
90
+
91
+ def involves_pacticipant_with_name?(pacticipant_name)
92
+ pacticipant_names.include?(pacticipant_name)
51
93
  end
52
94
  end
53
95
  end
@@ -1,13 +1,14 @@
1
1
  module PactBroker
2
2
  module Matrix
3
3
  class QueryResults < Array
4
- attr_reader :selectors, :options, :resolved_selectors
4
+ attr_reader :selectors, :options, :resolved_selectors, :integrations
5
5
 
6
- def initialize rows, selectors, options, resolved_selectors
6
+ def initialize rows, selectors, options, resolved_selectors, integrations
7
7
  super(rows)
8
8
  @selectors = selectors
9
9
  @resolved_selectors = resolved_selectors
10
10
  @options = options
11
+ @integrations = integrations
11
12
  end
12
13
 
13
14
  def rows
@@ -5,8 +5,8 @@ module PactBroker
5
5
  class QueryResultsWithDeploymentStatusSummary < QueryResults
6
6
  attr_reader :deployment_status_summary
7
7
 
8
- def initialize rows, selectors, options, resolved_selectors, deployment_status_summary
9
- super(rows, selectors, options, resolved_selectors)
8
+ def initialize rows, selectors, options, resolved_selectors, integrations, deployment_status_summary
9
+ super(rows, selectors, options, resolved_selectors, integrations)
10
10
  @deployment_status_summary = deployment_status_summary
11
11
  end
12
12
  end
@@ -0,0 +1,74 @@
1
+ module PactBroker
2
+ module Matrix
3
+ class Reason
4
+ def == other
5
+ self.class == other.class
6
+ end
7
+ end
8
+
9
+ class ErrorReason < Reason; end
10
+
11
+ class ErrorReasonWithTwoSelectors < ErrorReason
12
+ attr_reader :consumer_selector, :provider_selector
13
+
14
+ def initialize(consumer_selector, provider_selector)
15
+ @consumer_selector = consumer_selector
16
+ @provider_selector = provider_selector
17
+ end
18
+
19
+ def == other
20
+ super(other) &&
21
+ consumer_selector == other.consumer_selector &&
22
+ provider_selector == other.provider_selector
23
+ end
24
+
25
+ def to_s
26
+ "#{self.class} consumer_selector=#{consumer_selector}, provider_selector=#{provider_selector}"
27
+ end
28
+ end
29
+
30
+ # The pact for the required consumer version
31
+ # has never been verified by the provider
32
+ # (a row in the matrix with a blank provider version)
33
+ class PactNotEverVerifiedByProvider < ErrorReasonWithTwoSelectors; end
34
+
35
+ # The pact for the required consumer verison
36
+ # has been verified by the provider, but not by
37
+ # the required provider version
38
+ # (this row is not included in the matrix, and it's
39
+ # absence must be inferred)
40
+ class PactNotVerifiedByRequiredProviderVersion < ErrorReasonWithTwoSelectors; end
41
+
42
+ # The pact verification has failed
43
+ class VerificationFailed < ErrorReasonWithTwoSelectors; end
44
+
45
+ class VerificationFailedWithRow < ErrorReasonWithTwoSelectors; end
46
+
47
+ # The specified pacticipant version does not exist
48
+ class SpecifiedVersionDoesNotExist < ErrorReason
49
+ attr_reader :selector
50
+
51
+ def initialize(selector)
52
+ @selector = selector
53
+ end
54
+
55
+ def == other
56
+ super(other) && selector == other.selector
57
+ end
58
+
59
+ def to_s
60
+ "#{self.class} selector=#{selector}"
61
+ end
62
+ end
63
+
64
+ # The pact for the required consumer version has been
65
+ # successfully verified by the required provider version
66
+ class Successful < Reason
67
+ end
68
+
69
+ # There aren't any rows, but there are also no missing
70
+ # provider verifications.
71
+ class NoDependenciesMissing < Reason
72
+ end
73
+ end
74
+ end
@@ -5,6 +5,7 @@ require 'pact_broker/error'
5
5
  require 'pact_broker/matrix/query_results'
6
6
  require 'pact_broker/matrix/integration'
7
7
  require 'pact_broker/matrix/query_results_with_deployment_status_summary'
8
+ require 'pact_broker/matrix/resolved_selector'
8
9
 
9
10
  module PactBroker
10
11
  module Matrix
@@ -48,10 +49,10 @@ module PactBroker
48
49
  end
49
50
 
50
51
  # Return the latest matrix row (pact/verification) for each consumer_version_number/provider_version_number
51
- def find selectors, options = {}
52
- resolved_selectors = resolve_selectors(selectors, options)
52
+ def find specified_selectors, options = {}
53
+ resolved_selectors = resolve_selectors(specified_selectors, options)
53
54
  lines = query_matrix(resolved_selectors, options)
54
- lines = apply_latestby(options, selectors, lines)
55
+ lines = apply_latestby(options, specified_selectors, lines)
55
56
 
56
57
  # This needs to be done after the latestby, so can't be done in the db unless
57
58
  # the latestby logic is moved to the db
@@ -59,7 +60,9 @@ module PactBroker
59
60
  lines = lines.select{ |l| options[:success].include?(l.success) }
60
61
  end
61
62
 
62
- QueryResults.new(lines.sort, selectors, options, resolved_selectors)
63
+ integrations = find_integrations_for_specified_selectors(resolved_selectors.select(&:specified?))
64
+
65
+ QueryResults.new(lines.sort, specified_selectors, options, resolved_selectors, integrations)
63
66
  end
64
67
 
65
68
  def find_for_consumer_and_provider pacticipant_1_name, pacticipant_2_name
@@ -72,18 +75,35 @@ module PactBroker
72
75
  find(selectors, latestby: 'cvpv').select{|line| line.success }
73
76
  end
74
77
 
75
- def find_integrations(pacticipant_names)
76
- selectors = pacticipant_names.collect{ | pacticipant_name | add_ids(pacticipant_name: pacticipant_name) }
78
+ # If one pacticipant is specified, find all the integrations that involve that pacticipant
79
+ # If two or more are specified, just return the integrations that involve the specified pacticipants
80
+ def find_integrations_for_specified_selectors(resolved_specified_selectors)
81
+ specified_pacticipant_names = resolved_specified_selectors.collect(&:pacticipant_name)
77
82
  Row
78
83
  .select(:consumer_name, :consumer_id, :provider_name, :provider_id)
79
- .matching_selectors(selectors)
84
+ .matching_selectors(resolved_specified_selectors)
80
85
  .distinct
81
86
  .all
82
- .collect{ |row | Integration.from_hash(row.to_hash) }.uniq
87
+ .collect do |row |
88
+ row.to_hash
89
+ end
90
+ .uniq
91
+ .collect do | hash |
92
+ required = is_a_row_for_this_integration_required?(specified_pacticipant_names, hash[:consumer_name])
93
+ Integration.from_hash(hash.merge(required: required))
94
+ end
83
95
  end
84
96
 
85
97
  private
86
98
 
99
+ # If one of the specified pacticipants is a consumer, then that provider is required to be deployed
100
+ # to the same environment before the consumer can be deployed.
101
+ # If one of the specified pacticipants is a provider, then the provider may be deployed
102
+ # without the consumer being present.
103
+ def is_a_row_for_this_integration_required?(specified_pacticipant_names, consumer_name)
104
+ specified_pacticipant_names.include?(consumer_name)
105
+ end
106
+
87
107
  def apply_latestby options, selectors, lines
88
108
  return lines unless options[:latestby]
89
109
  group_by_columns = case options[:latestby]
@@ -114,7 +134,7 @@ module PactBroker
114
134
  end
115
135
 
116
136
  def query_matrix selectors, options
117
- query = view_for(options).select_all.matching_selectors(selectors)
137
+ query = Row.select_all.matching_selectors(selectors)
118
138
  query = query.limit(options[:limit]) if options[:limit]
119
139
  query
120
140
  .order_by_names_ascending_most_recent_first
@@ -123,97 +143,113 @@ module PactBroker
123
143
  .all
124
144
  end
125
145
 
126
- def view_for(options)
127
- Row
128
- end
129
-
130
- def resolve_selectors(selectors, options)
131
- resolved_selectors = look_up_version_numbers(selectors, options)
146
+ def resolve_selectors(specified_selectors, options)
147
+ resolved_specified_selectors = resolve_versions_and_add_ids(specified_selectors, :specified)
132
148
  if options[:latest] || options[:tag]
133
- apply_latest_and_tag_to_inferred_selectors(resolved_selectors, options)
149
+ add_inferred_selectors(resolved_specified_selectors, options)
134
150
  else
135
- resolved_selectors
151
+ resolved_specified_selectors
136
152
  end
137
153
  end
138
154
 
139
155
  # Find the version number for selectors with the latest and/or tag specified
140
- def look_up_version_numbers(selectors, options)
156
+ def resolve_versions_and_add_ids(selectors, selector_type)
141
157
  selectors.collect do | selector |
142
- if selector[:tag] && selector[:latest]
143
- version = version_repository.find_by_pacticipant_name_and_latest_tag(selector[:pacticipant_name], selector[:tag])
144
- raise Error.new("No version of #{selector[:pacticipant_name]} found with tag #{selector[:tag]}") unless version
145
- # validation in resource should ensure we always have a version
146
- {
147
- pacticipant_name: selector[:pacticipant_name],
148
- pacticipant_version_number: version.number
149
- }
150
- elsif selector[:latest]
151
- version = version_repository.find_latest_by_pacticpant_name(selector[:pacticipant_name])
152
- raise Error.new("No version of #{selector[:pacticipant_name]} found") unless version
153
- {
154
- pacticipant_name: selector[:pacticipant_name],
155
- pacticipant_version_number: version.number
156
- }
157
- elsif selector[:tag]
158
- # validation in resource should ensure we always have at least one version
159
- versions = version_repository.find_by_pacticipant_name_and_tag(selector[:pacticipant_name], selector[:tag])
160
- raise Error.new("No version of #{selector[:pacticipant_name]} found with tag #{selector[:tag]}") unless versions.any?
161
- versions.collect do | version |
162
- {
163
- pacticipant_name: selector[:pacticipant_name],
164
- pacticipant_version_number: version.number
165
- }
158
+ pacticipant = PactBroker::Domain::Pacticipant.find(name: selector[:pacticipant_name])
159
+ versions = find_versions_for_selector(selector)
160
+ build_selectors_for_pacticipant_and_versions(pacticipant, versions, selector, selector_type)
161
+ end.flatten
162
+ end
163
+
164
+ def build_selectors_for_pacticipant_and_versions(pacticipant, versions, original_selector, selector_type)
165
+ if versions
166
+ versions.collect do | version |
167
+ if version
168
+ selector_for_version(pacticipant, version, original_selector, selector_type)
169
+ else
170
+ selector_for_non_existing_version(pacticipant, original_selector, selector_type)
166
171
  end
167
- else
168
- selector.dup
169
172
  end
170
- end.flatten.compact.collect do | selector |
171
- add_ids(selector)
173
+ else
174
+ selector_without_version(pacticipant, selector_type)
172
175
  end
173
176
  end
174
177
 
175
- def add_ids(selector)
178
+ def find_versions_for_selector(selector)
179
+ if selector[:tag] && selector[:latest]
180
+ version = version_repository.find_by_pacticipant_name_and_latest_tag(selector[:pacticipant_name], selector[:tag])
181
+ [version]
182
+ elsif selector[:latest]
183
+ version = version_repository.find_latest_by_pacticpant_name(selector[:pacticipant_name])
184
+ [version]
185
+ elsif selector[:tag]
186
+ versions = version_repository.find_by_pacticipant_name_and_tag(selector[:pacticipant_name], selector[:tag])
187
+ versions.any? ? versions : [nil]
188
+ elsif selector[:pacticipant_version_number]
189
+ version = version_repository.find_by_pacticipant_name_and_number(selector[:pacticipant_name], selector[:pacticipant_version_number])
190
+ [version]
191
+ else
192
+ nil
193
+ end
194
+ end
195
+
196
+ def add_ids_to_selector(selector)
176
197
  if selector[:pacticipant_name]
177
198
  pacticipant = PactBroker::Domain::Pacticipant.find(name: selector[:pacticipant_name])
178
199
  selector[:pacticipant_id] = pacticipant ? pacticipant.id : nil
179
200
  end
180
201
 
181
- if selector[:pacticipant_name] && selector[:pacticipant_version_number]
202
+ if selector[:pacticipant_name] && selector[:pacticipant_version_number] && !selector[:pacticipant_version_id]
182
203
  version = version_repository.find_by_pacticipant_name_and_number(selector[:pacticipant_name], selector[:pacticipant_version_number])
183
204
  selector[:pacticipant_version_id] = version ? version.id : nil
184
205
  end
185
206
 
186
- if selector[:pacticipant_version_number].nil?
187
- selector[:pacticipant_version_id] = nil
207
+ if !selector.key?(:pacticipant_version_id)
208
+ selector[:pacticipant_version_id] = nil
188
209
  end
189
210
  selector
190
211
  end
191
212
 
192
- # eg. when checking to see if Foo version 2 can be deployed to prod,
193
- # need to look up all the 'partner' pacticipants, and determine their latest prod versions
194
- def apply_latest_and_tag_to_inferred_selectors(selectors, options)
195
- all_pacticipant_names = all_pacticipant_names_in_specified_matrix(selectors)
196
- specified_names = selectors.collect{ |s| s[:pacticipant_name] }
197
- inferred_names = all_pacticipant_names - specified_names
213
+ # When only one selector is specified, (eg. checking to see if Foo version 2 can be deployed to prod),
214
+ # need to look up all integrated pacticipants, and determine their relevant (eg. latest prod) versions
215
+ def add_inferred_selectors(resolved_specified_selectors, options)
216
+ integrations = find_integrations_for_specified_selectors(resolved_specified_selectors)
217
+ all_pacticipant_names = integrations.collect(&:pacticipant_names).flatten.uniq
218
+ specified_names = resolved_specified_selectors.collect{ |s| s[:pacticipant_name] }
219
+ inferred_pacticipant_names = all_pacticipant_names - specified_names
220
+ resolved_specified_selectors + build_inferred_selectors(inferred_pacticipant_names, options)
221
+ end
198
222
 
199
- inferred_selectors = inferred_names.collect do | pacticipant_name |
223
+ def build_inferred_selectors(inferred_pacticipant_names, options)
224
+ selectors = inferred_pacticipant_names.collect do | pacticipant_name |
200
225
  selector = {
201
- pacticipant_name: pacticipant_name,
226
+ pacticipant_name: pacticipant_name
202
227
  }
203
228
  selector[:tag] = options[:tag] if options[:tag]
204
229
  selector[:latest] = options[:latest] if options[:latest]
205
230
  selector
206
231
  end
207
-
208
- selectors + look_up_version_numbers(inferred_selectors, options)
232
+ resolve_versions_and_add_ids(selectors, :inferred)
209
233
  end
210
234
 
211
235
  def all_pacticipant_names_in_specified_matrix(selectors)
212
- find_integrations(selectors.collect{|s| s[:pacticipant_name]})
236
+ find_integrations_for_specified_selectors(selectors)
213
237
  .collect(&:pacticipant_names)
214
238
  .flatten
215
239
  .uniq
216
240
  end
241
+
242
+ def selector_for_non_existing_version(pacticipant, original_selector, selector_type)
243
+ ResolvedSelector.for_pacticipant_and_non_existing_version(pacticipant, original_selector, selector_type)
244
+ end
245
+
246
+ def selector_for_version(pacticipant, version, original_selector, selector_type)
247
+ ResolvedSelector.for_pacticipant_and_version(pacticipant, version, original_selector, selector_type)
248
+ end
249
+
250
+ def selector_without_version(pacticipant, selector_type)
251
+ ResolvedSelector.for_pacticipant(pacticipant, selector_type)
252
+ end
217
253
  end
218
254
  end
219
255
  end