class PactBroker::Matrix::Repository
Constants
- GROUP_BY_PACT
- GROUP_BY_PROVIDER
- GROUP_BY_PROVIDER_VERSION_NUMBER
- TP_COLS
TODO move latest verification logic in to database
Public Instance Methods
Return the latest matrix row (pact/verification) for each consumer_version_number/provider_version_number
# File lib/pact_broker/matrix/repository.rb, line 60 def find specified_selectors, options = {} resolved_ignore_selectors = resolve_ignore_selectors(options) resolved_specified_selectors = resolve_versions_and_add_ids(specified_selectors, :specified, resolved_ignore_selectors) integrations = find_integrations_for_specified_selectors(resolved_specified_selectors, options) resolved_selectors = add_any_inferred_selectors(resolved_specified_selectors, resolved_ignore_selectors, integrations, options) considered_rows, ignored_rows = find_considered_and_ignored_rows(resolved_selectors, resolved_ignore_selectors, options) QueryResults.new(considered_rows.sort, ignored_rows.sort, specified_selectors, options, resolved_selectors, resolved_ignore_selectors, integrations) end
# File lib/pact_broker/matrix/repository.rb, line 69 def find_for_consumer_and_provider pacticipant_1_name, pacticipant_2_name selectors = [ UnresolvedSelector.new(pacticipant_name: pacticipant_1_name), UnresolvedSelector.new(pacticipant_name: pacticipant_2_name)] options = { latestby: "cvpv" } find(selectors, options) end
rubocop: disable Metrics/CyclomaticComplexity
# File lib/pact_broker/matrix/repository.rb, line 34 def find_ids_for_pacticipant_names params criteria = {} if params[:consumer_name] || params[:provider_name] if params[:consumer_name] pacticipant = PactBroker::Domain::Pacticipant.where(name_like(:name, params[:consumer_name])).single_record criteria[:consumer_id] = pacticipant.id if pacticipant end if params[:provider_name] pacticipant = PactBroker::Domain::Pacticipant.where(name_like(:name, params[:provider_name])).single_record criteria[:provider_id] = pacticipant.id if pacticipant end end if params[:pacticipant_name] pacticipant = PactBroker::Domain::Pacticipant.where(name_like(:name, params[:pacticipant_name])).single_record criteria[:pacticipant_id] = pacticipant.id if pacticipant end criteria[:tag_name] = params[:tag_name] if params[:tag_name].is_a?(String) # Could be a sym from resource parameters in api.rb criteria end
Private Instance Methods
# File lib/pact_broker/matrix/repository.rb, line 155 def add_any_inferred_selectors(resolved_specified_selectors, resolved_ignore_selectors, integrations, options) if infer_selectors_for_integrations?(options) resolved_specified_selectors + inferred_selectors(resolved_specified_selectors, resolved_ignore_selectors, integrations, options) else resolved_specified_selectors end end
rubocop: disable Metrics/CyclomaticComplexity It would be nicer to do this in the SQL, but it requires time that I don't have at the moment
# File lib/pact_broker/matrix/repository.rb, line 183 def apply_latestby options, lines return lines unless options[:latestby] group_by_columns = case options[:latestby] when "cvpv" then GROUP_BY_PROVIDER_VERSION_NUMBER when "cvp" then GROUP_BY_PROVIDER when "cp" then GROUP_BY_PACT end # The group with the nil provider_version_numbers will be the results of the left outer join # that don't have verifications, so we need to include them all. lines.group_by{|line| group_by_columns.collect{|key| line.send(key) }} .values .collect{ | line | line.first.provider_version_number.nil? ? line : line.sort_by(&:provider_version_order).last } .flatten end
# File lib/pact_broker/matrix/repository.rb, line 163 def apply_success_filter(rows_with_latest_by_applied, options) # This needs to be done after the latestby, so can't be done in the db unless # the latestby logic is moved to the db if options.key?(:success) rows_with_latest_by_applied.select{ |l| options[:success].include?(l.success) } else rows_with_latest_by_applied end end
# File lib/pact_broker/matrix/repository.rb, line 209 def base_model(options = {}) options[:latestby] ? QuickRow : EveryRow end
To make it easy for pf to override
# File lib/pact_broker/matrix/repository.rb, line 218 def base_model_for_integrations QuickRow end
# File lib/pact_broker/matrix/repository.rb, line 278 def build_inferred_selectors(inferred_pacticipant_names, resolved_ignore_selectors, options) selectors = inferred_pacticipant_names.collect do | pacticipant_name | selector = UnresolvedSelector.new(pacticipant_name: pacticipant_name) selector.tag = options[:tag] if options[:tag] selector.branch = options[:branch] if options[:branch] selector.latest = options[:latest] if options[:latest] selector.environment_name = options[:environment_name] if options[:environment_name] selector end resolve_versions_and_add_ids(selectors, :inferred, resolved_ignore_selectors) end
When a single selector specifies multiple versions (eg. “all prod pacts”), this expands the single selector into one selector for each version.
# File lib/pact_broker/matrix/repository.rb, line 250 def build_resolved_selectors(pacticipant, versions, unresolved_selector, selector_type, resolved_ignore_selectors) if versions one_of_many = versions.compact.size > 1 versions.collect do | version | if version selector_for_found_version(pacticipant, version, unresolved_selector, selector_type, one_of_many, resolved_ignore_selectors) else selector_for_non_existing_version(pacticipant, unresolved_selector, selector_type, resolved_ignore_selectors) end end else selector_for_all_versions_of_a_pacticipant(pacticipant, unresolved_selector, selector_type, resolved_ignore_selectors) end end
# File lib/pact_broker/matrix/repository.rb, line 148 def deduplicate_integrations(integrations) integrations .group_by{ | integration| [integration.consumer_id, integration.provider_id] } .values .collect { | duplicate_integrations | duplicate_integrations.find(&:required?) || duplicate_integrations.first } end
# File lib/pact_broker/matrix/repository.rb, line 77 def find_considered_and_ignored_rows(resolved_selectors, resolved_ignore_selectors, options) rows = query_matrix(resolved_selectors, options) rows = apply_latestby(options, rows) rows = apply_success_filter(rows, options) considered_rows, ignored_rows = split_rows_into_considered_and_ignored(rows, resolved_ignore_selectors) return considered_rows, ignored_rows end
# File lib/pact_broker/matrix/repository.rb, line 85 def find_integrations_for_specified_selectors(resolved_specified_selectors, options) if infer_selectors_for_integrations?(options) find_integrations_for_specified_selectors_with_inferred_integrations(resolved_specified_selectors, options) else find_integrations_for_specified_selectors_only(resolved_specified_selectors) end end
# File lib/pact_broker/matrix/repository.rb, line 93 def find_integrations_for_specified_selectors_only(resolved_specified_selectors) specified_pacticipant_names = resolved_specified_selectors.collect(&:pacticipant_name) base_model_for_integrations .distinct_integrations(resolved_specified_selectors, false) .collect(&:to_hash) .collect do | integration_hash | required = is_a_row_for_this_integration_required?(specified_pacticipant_names, integration_hash[:consumer_name]) Integration.from_hash(integration_hash.merge(required: required)) end end
# File lib/pact_broker/matrix/repository.rb, line 104 def find_integrations_for_specified_selectors_with_inferred_integrations(resolved_specified_selectors, options) integrations = integrations_where_specified_selector_is_consumer(resolved_specified_selectors) + integrations_where_specified_selector_is_provider(resolved_specified_selectors, options) deduplicate_integrations(integrations) end
# File lib/pact_broker/matrix/repository.rb, line 235 def find_versions_for_selector(selector) # For selectors that just set the pacticipant name, there's no need to resolve the version - # only the pacticipant ID will be used in the query return nil if selector.all_for_pacticipant? versions = version_repository.find_versions_for_selector(selector) if selector.latest [versions.first] else versions.empty? ? [nil] : versions end end
# File lib/pact_broker/matrix/repository.rb, line 337 def ignore_row?(resolved_ignore_selectors, row) resolved_ignore_selectors.any? do | s | s.pacticipant_id == row.consumer_id && (s.only_pacticipant_name_specified? || s.pacticipant_version_id == row.consumer_version_id) || s.pacticipant_id == row.provider_id && (s.only_pacticipant_name_specified? || s.pacticipant_version_id == row.provider_version_id) end end
# File lib/pact_broker/matrix/repository.rb, line 265 def infer_selectors_for_integrations?(options) options[:latest] || options[:tag] || options[:branch] || options[:environment_name] end
When only one selector is specified, (eg. checking to see if Foo version 2 can be deployed to prod), need to look up all integrated pacticipants, and determine their relevant (eg. latest prod) versions
# File lib/pact_broker/matrix/repository.rb, line 271 def inferred_selectors(resolved_specified_selectors, resolved_ignore_selectors, integrations, options) all_pacticipant_names = integrations.collect(&:pacticipant_names).flatten.uniq specified_names = resolved_specified_selectors.collect{ |s| s[:pacticipant_name] } inferred_pacticipant_names = all_pacticipant_names - specified_names build_inferred_selectors(inferred_pacticipant_names, resolved_ignore_selectors, options) end
# File lib/pact_broker/matrix/repository.rb, line 110 def integrations_where_specified_selector_is_consumer(resolved_specified_selectors) resolved_specified_selectors.flat_map do | selector | base_model_for_integrations .distinct_integrations_for_selector_as_consumer(selector) .all .collect do | integration | Integration.from_hash( consumer_id: integration[:consumer_id], consumer_name: integration[:consumer_name], provider_id: integration[:provider_id], provider_name: integration[:provider_name], required: true ) end end end
# File lib/pact_broker/matrix/repository.rb, line 127 def integrations_where_specified_selector_is_provider(resolved_specified_selectors, options) integrations_involving_specified_providers = PactBroker::Integrations::Integration .where(provider_id: resolved_specified_selectors.collect(&:pacticipant_id)) .eager(:consumer) .all destination_selector = PactBroker::Matrix::UnresolvedSelector.new(options.slice(:latest, :tag, :branch, :environment_name).compact) integrations_involving_specified_providers.collect do | integration | required = PactBroker::Domain::Version.where(pacticipant: integration.consumer).for_selector(destination_selector).any? Integration.from_hash( consumer_id: integration.consumer.id, consumer_name: integration.consumer.name, provider_id: integration.provider.id, provider_name: integration.provider.name, required: required ) end end
If a specified pacticipant is a consumer, then its provider is required to be deployed to the same environment before the consumer can be deployed. If a specified pacticipant is a provider only, then it may be deployed without the consumer being present.
# File lib/pact_broker/matrix/repository.rb, line 177 def is_a_row_for_this_integration_required?(specified_pacticipant_names, consumer_name) specified_pacticipant_names.include?(consumer_name) end
rubocop: enable Metrics/CyclomaticComplexity
# File lib/pact_broker/matrix/repository.rb, line 200 def query_matrix selectors, options query = base_model(options).select_all_columns .matching_selectors(selectors) .order_by_last_action_date query = query.limit(options[:limit]) if options[:limit] query.eager_all_the_things.all end
# File lib/pact_broker/matrix/repository.rb, line 213 def resolve_ignore_selectors(options) resolve_versions_and_add_ids(options.fetch(:ignore_selectors, []), :ignored) end
Find the version number for selectors with the latest and/or tag specified
# File lib/pact_broker/matrix/repository.rb, line 223 def resolve_versions_and_add_ids(unresolved_selectors, selector_type, resolved_ignore_selectors = []) unresolved_selectors.collect do | unresolved_selector | pacticipant = PactBroker::Domain::Pacticipant.find(name: unresolved_selector.pacticipant_name) if pacticipant versions = find_versions_for_selector(unresolved_selector) build_resolved_selectors(pacticipant, versions, unresolved_selector, selector_type, resolved_ignore_selectors) else selector_for_non_existing_pacticipant(unresolved_selector, selector_type) end end.flatten end
rubocop: enable Metrics/ParameterLists
# File lib/pact_broker/matrix/repository.rb, line 306 def selector_for_all_versions_of_a_pacticipant(pacticipant, unresolved_selector, selector_type, resolved_ignore_selectors) # Doesn't make sense to ignore this, as you can't have a can-i-deploy query # for "all versions of a pacticipant". But whatever. ignore = resolved_ignore_selectors.any? do | s | s.pacticipant_id == pacticipant.id && s.only_pacticipant_name_specified? end ResolvedSelector.for_pacticipant(pacticipant, unresolved_selector, selector_type, ignore) end
rubocop: disable Metrics/ParameterLists
# File lib/pact_broker/matrix/repository.rb, line 298 def selector_for_found_version(pacticipant, version, unresolved_selector, selector_type, one_of_many, resolved_ignore_selectors) ignore = resolved_ignore_selectors.any? do | s | s.pacticipant_id == pacticipant.id && (s.only_pacticipant_name_specified? || s.pacticipant_version_id == version.id) end ResolvedSelector.for_pacticipant_and_version(pacticipant, version, unresolved_selector, selector_type, ignore, one_of_many) end
only relevant for ignore selectors, validation stops this happening for the normal selectors
# File lib/pact_broker/matrix/repository.rb, line 317 def selector_for_non_existing_pacticipant(unresolved_selector, selector_type) ResolvedSelector.for_non_existing_pacticipant(unresolved_selector, selector_type, false) end
# File lib/pact_broker/matrix/repository.rb, line 290 def selector_for_non_existing_version(pacticipant, unresolved_selector, selector_type, resolved_ignore_selectors) ignore = resolved_ignore_selectors.any? do | s | s.pacticipant_id == pacticipant.id && s.only_pacticipant_name_specified? end ResolvedSelector.for_pacticipant_and_non_existing_version(pacticipant, unresolved_selector, selector_type, ignore) end
# File lib/pact_broker/matrix/repository.rb, line 321 def split_rows_into_considered_and_ignored(rows, resolved_ignore_selectors) if resolved_ignore_selectors.any? considered, ignored = [], [] rows.each do | row | if ignore_row?(resolved_ignore_selectors, row) ignored << row else considered << row end end return considered, ignored else return rows, [] end end