Skip to content

Commit

Permalink
feat(pacts for verification): if no consumer version selectors are sp…
Browse files Browse the repository at this point in the history
…ecified, return the pacts for the latest main version, and all the deployed and released versions
  • Loading branch information
bethesque committed Aug 8, 2021
1 parent 63e287e commit 5fccd52
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 48 deletions.
4 changes: 4 additions & 0 deletions lib/pact_broker/integrations/integration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ def latest_pact_or_verification_publication_date
def latest_verification_publication_date
latest_verification&.execution_date
end

def <=>(other)
[consumer.name.downcase, provider.name.downcase] <=> [other.consumer.name.downcase, other.provider.name.downcase]
end
end
end
end
Expand Down
6 changes: 4 additions & 2 deletions lib/pact_broker/integrations/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
require "pact_broker/integrations/integration"
require "pact_broker/db/models"
require "pact_broker/repositories/helpers"
require "pact_broker/repositories/scopes"

module PactBroker
module Integrations
class Service
extend PactBroker::Repositories
extend PactBroker::Services
include PactBroker::Logging
extend PactBroker::Repositories::Scopes

def self.find_all
# The only reason the pact_version needs to be loaded is that
Expand Down Expand Up @@ -60,8 +62,8 @@ def self.delete_all
end
end

def self.scope_for(scope)
PactBroker.policy_scope!(scope)
def self.find_for_provider(provider)
scope_for(PactBroker::Integrations::Integration).where(provider_id: provider.id).eager(:consumer).eager(:provider).all.sort
end
end
end
Expand Down
69 changes: 44 additions & 25 deletions lib/pact_broker/pacts/pacts_for_verification_repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,39 +99,58 @@ def find_pacts_for_fallback_tags(selected_pacts, provider_name, consumer_version
end
end

# rubocop: disable Metrics/CyclomaticComplexity
def find_pacts_by_selector(provider_name, consumer_version_selectors)
provider = pacticipant_repository.find_by_name(provider_name)

selectors = if consumer_version_selectors.empty?
Selectors.create_for_overall_latest
else
consumer_version_selectors.select(&:all_for_tag?) +
consumer_version_selectors.select(&:latest_for_tag?) +
consumer_version_selectors.select(&:latest_for_branch?) +
consumer_version_selectors.select(&:latest_for_main_branch?) +
consumer_version_selectors.select(&:overall_latest?) +
consumer_version_selectors.select(&:currently_deployed?) +
consumer_version_selectors.select(&:currently_supported?)
end

selectors.flat_map do | selector |
specified_selectors_or_defaults(consumer_version_selectors, provider).flat_map do | selector |
query = scope_for(PactPublication).for_provider_and_consumer_version_selector(provider, selector)
query.all.collect do | pact_publication |
resolved_selector = if selector.currently_deployed? || selector.currently_supported?
environment = environment_service.find_by_name(pact_publication.values.fetch(:environment_name))
selector.resolve_for_environment(pact_publication.consumer_version, environment, pact_publication.values[:target])
else
selector.resolve(pact_publication.consumer_version)
end
SelectedPact.new(
pact_publication.to_domain,
Selectors.new(resolved_selector)
)
create_selected_pact(pact_publication, selector)
end
end
end

def create_selected_pact(pact_publication, selector)
resolved_selector = if selector.currently_deployed? || selector.currently_supported?
environment = environment_service.find_by_name(pact_publication.values.fetch(:environment_name))
selector.resolve_for_environment(pact_publication.consumer_version, environment, pact_publication.values[:target])
else
selector.resolve(pact_publication.consumer_version)
end
SelectedPact.new(pact_publication.to_domain, Selectors.new(resolved_selector))
end

def specified_selectors_or_defaults(consumer_version_selectors, provider)
if consumer_version_selectors.empty?
default_selectors(provider)
else
consumer_version_selectors
end
end

def default_selectors(provider)
selectors = selector_for_latest_main_version_or_overall_latest(provider)
selectors << Selector.for_currently_deployed
selectors << Selector.for_currently_supported
selectors
end

def selector_for_latest_main_version_or_overall_latest(provider)
selectors = Selectors.new
consumers = integration_service.find_for_provider(provider).collect(&:consumer)

consumers.collect do | consumer |
if consumer.main_branch && PactBroker::Domain::Version.for_selector(PactBroker::Matrix::UnresolvedSelector.new(branch: consumer.main_branch, latest: true)).any?
selectors << Selector.for_main_branch.for_consumer(consumer.name)
elsif consumer.main_branch && PactBroker::Domain::Version.for_selector(PactBroker::Matrix::UnresolvedSelector.new(tag: consumer.main_branch, latest: true)).any?
selectors << Selector.latest_for_tag(consumer.main_branch).for_consumer(consumer.name)
else
selectors << Selector.overall_latest.for_consumer(consumer.name)
end
end

selectors
end
# rubocop: enable Metrics/CyclomaticComplexity

def find_pacts_for_which_the_latest_version_for_the_fallback_tag_is_required(provider_name, selectors)
selectors.collect do | selector |
Expand Down
8 changes: 6 additions & 2 deletions lib/pact_broker/pacts/selector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def currently_deployed
end

def currently_deployed?
currently_deployed
!!currently_deployed
end

def currently_supported= currently_supported
Expand All @@ -113,7 +113,7 @@ def currently_supported
end

def currently_supported?
currently_supported
!!currently_supported
end

def environment_name= environment_name
Expand Down Expand Up @@ -204,6 +204,10 @@ def self.from_hash hash
Selector.new(hash)
end

def for_consumer(consumer)
Selector.new(to_h.merge(consumer: consumer))
end

def latest_for_main_branch?
!!main_branch
end
Expand Down
2 changes: 1 addition & 1 deletion lib/pact_broker/versions/repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def set_branch_if_unset(version, branch)
version.update(branch: branch) if version.branch.nil?
version
end

def find_latest_version_from_main_branch(pacticipant)
if pacticipant.main_branch
latest_from_main_branch = PactBroker::Domain::Version
Expand Down
122 changes: 104 additions & 18 deletions spec/lib/pact_broker/pacts/repository_find_for_verification_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,112 @@ def find_by_consumer_name_and_consumer_version_number(consumer_name, consumer_ve
subject { Repository.new.find_for_verification("Bar", consumer_version_selectors) }

context "when there are no selectors" do
before do
td.create_pact_with_hierarchy("Foo", "foo-latest-prod-version", "Bar")
.create_consumer_version_tag("prod")
.create_consumer_version("not-latest-dev-version", tag_names: ["dev"])
.comment("next pact not selected")
.create_pact
.create_consumer_version("foo-latest-dev-version", tag_names: ["dev"])
.create_pact
.create_consumer("Baz")
.create_consumer_version("baz-latest-dev-version", tag_names: ["dev"])
.create_pact
end

let(:foo_main_branch) { nil }

let(:consumer_version_selectors) { Selectors.new }

it "returns the latest pact for each consumer" do
expect(subject.size).to eq 2
expect(find_by_consumer_name_and_consumer_version_number("Foo", "foo-latest-dev-version")).to_not be nil
expect(find_by_consumer_name_and_consumer_version_number("Baz", "baz-latest-dev-version")).to_not be nil
expect(subject.all?(&:overall_latest?)).to be true
context "when there is no main branch version" do
before do
td.create_consumer("Foo")
.create_pact_with_hierarchy("Foo", "foo-latest-prod-version", "Bar")
.create_consumer_version_tag("prod")
.create_consumer_version("not-latest-dev-version", tag_names: ["dev"])
.comment("next pact not selected")
.create_pact
.create_consumer_version("foo-latest-dev-version", tag_names: ["dev"])
.create_pact
.create_consumer("Baz")
.create_consumer_version("baz-latest-dev-version", tag_names: ["dev"])
.create_pact
end

it "returns the latest pact for each consumer" do
expect(subject.size).to eq 2
expect(find_by_consumer_name_and_consumer_version_number("Foo", "foo-latest-dev-version")).to_not be nil
expect(find_by_consumer_name_and_consumer_version_number("Baz", "baz-latest-dev-version")).to_not be nil
expect(subject.all?(&:overall_latest?)).to be true
end
end

context "when there is a version from the main branch" do
before do
td.create_consumer("Foo", main_branch: "main")
.create_consumer_version("1", branch: "main")
.create_provider("Bar")
.create_pact
.create_pact_with_hierarchy("Foo", "2", "Bar")
end

it "returns the latest version from the main branch" do
expect(subject.size).to eq 1
expect(find_by_consumer_name_and_consumer_version_number("Foo", "1")).to_not be_nil
expect(subject.first.selectors.first).to be_latest_for_main_branch
end
end

context "when there is a version with a tag with the name of the main branch" do
before do
td.create_consumer("Foo", main_branch: "main")
.create_consumer_version("1", tag_name: "main")
.create_provider("Bar")
.create_pact
.create_pact_with_hierarchy("Foo", "2", "Bar")
end

it "returns the latest version from the main branch" do
expect(subject.size).to eq 1
expect(find_by_consumer_name_and_consumer_version_number("Foo", "1")).to_not be_nil
expect(subject.first.selectors.first).to be_latest_for_tag
expect(subject.first.selectors.first.tag).to eq "main"
end
end

context "when there is a not version from the main branch" do
before do
td.create_pact_with_hierarchy("Foo", "1", "Bar")
.create_pact_with_hierarchy("Foo", "2", "Bar")
end

it "returns the latest version from the main branch" do
expect(subject.size).to eq 1
expect(find_by_consumer_name_and_consumer_version_number("Foo", "2")).to_not be_nil
expect(subject.first.selectors.first).to be_overall_latest
end
end

context "when there are currently deployed versons" do
before do
td.create_environment("test")
.create_pact_with_hierarchy("Foo", "1", "Bar")
.create_deployed_version_for_consumer_version(currently_deployed: false)
.create_pact_with_hierarchy("Foo", "2", "Bar")
.create_deployed_version_for_consumer_version
.create_pact_with_hierarchy("Foo", "3", "Bar")
end

it "returns the currently deployed pacts" do
expect(find_by_consumer_name_and_consumer_version_number("Foo", "1")).to be_nil
expect(find_by_consumer_name_and_consumer_version_number("Foo", "2")).to_not be_nil
expect(find_by_consumer_name_and_consumer_version_number("Foo", "2").selectors.first).to be_currently_deployed
end
end

context "when there are currently released+supported versions" do
before do
td.create_environment("test")
.create_pact_with_hierarchy("Foo", "1", "Bar")
.create_released_version_for_consumer_version(currently_supported: false)
.create_pact_with_hierarchy("Foo", "2", "Bar")
.create_released_version_for_consumer_version
.create_pact_with_hierarchy("Foo", "3", "Bar")
end

it "returns the currently deployed pacts" do
expect(find_by_consumer_name_and_consumer_version_number("Foo", "1")).to be_nil
expect(find_by_consumer_name_and_consumer_version_number("Foo", "2")).to_not be_nil
expect(find_by_consumer_name_and_consumer_version_number("Foo", "2").selectors.first).to be_currently_supported
end
end
end

Expand Down Expand Up @@ -267,7 +353,7 @@ def find_by_consumer_name_and_consumer_version_number(consumer_name, consumer_ve
end

it "does not set the tag name" do
expect(find_by_consumer_version_number("foo-latest-dev-version").selectors).to eq [ResolvedSelector.new({ latest: true }, PactBroker::Domain::Version.find(number: "foo-latest-dev-version"))]
expect(find_by_consumer_version_number("foo-latest-dev-version").selectors).to eq [ResolvedSelector.new({ latest: true, consumer: "Foo" }, PactBroker::Domain::Version.find(number: "foo-latest-dev-version"))]
expect(find_by_consumer_version_number("foo-latest-dev-version").overall_latest?).to be true
end
end
Expand Down

0 comments on commit 5fccd52

Please sign in to comment.