Skip to content

Commit

Permalink
feat: add provider pacts by branch endpoints
Browse files Browse the repository at this point in the history
            "pb:latest-branch-pact-version" =>
             {
               href: base_url + "/pacts/provider/{provider}/consumer/{consumer}/branch/{branch}/latest",
               title: "Latest version of a pact for a given consumer, provider and consumer version branch",
               templated: false
             },
             "pb:branch-pact-versions" =>
             {
               href: base_url + "/pacts/provider/{provider}/consumer/{consumer}/branch/{branch}",
               title: "All versions of a pact for a given consumer, provider and consumer version branch",
               templated: false
             },
            "pb:latest-provider-pacts-with-branch" =>
            {
              href: base_url + "/pacts/provider/{provider}/branch/{branch}/latest",
              title: "Latest pacts for provider with the specified branch",
              templated: true
            },
            "pb:provider-pacts-with-branch" =>
            {
              href: base_url + "/pacts/provider/{provider}/branch/{branch}",
              title: "All pact versions for the provider with the specified consumer version branch",
              templated: true
            }
  • Loading branch information
YOU54F committed Feb 13, 2025
1 parent cf3e55b commit 2d8a2dd
Show file tree
Hide file tree
Showing 15 changed files with 245 additions and 2 deletions.
6 changes: 6 additions & 0 deletions lib/pact_broker/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ def self.build_api(application_context = PactBroker::ApplicationContext.default_
add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "versions"], Api::Resources::PactVersions, {resource_name: "pact_publications"}
add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "versions", :consumer_version_number], Api::Resources::Pact, {resource_name: "pact_publication", deprecated: true} # Not the standard URL, but keep for backwards compatibility
add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "tag", :tag], Api::Resources::TaggedPactVersions, {resource_name: "tagged_pact_publications"}
add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "branch"], Api::Resources::PactVersionsForBranch, {resource_name: "pact_publications_for_main_branch"}
add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "branch", "latest"], Api::Resources::PactVersionsForBranch, {resource_name: "latest_pact_publications_for_main_branch"}
add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "branch", :branch_name], Api::Resources::PactVersionsForBranch, {resource_name: "pact_publications_for_branch"}

# Pacts
Expand All @@ -43,6 +45,8 @@ def self.build_api(application_context = PactBroker::ApplicationContext.default_
add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "version", :consumer_version_number, "diff", "previous-distinct"], Api::Resources::PactContentDiff, {resource_name: "previous_distinct_pact_version_diff"}
add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "version", :consumer_version_number, "diff", "version", :comparison_consumer_version], Api::Resources::PactContentDiff, {resource_name: "pact_version_diff_by_consumer_version"}
add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "pact-version", :pact_version_sha, "diff", "pact-version", :comparison_pact_version_sha], Api::Resources::PactContentDiff, {resource_name: "pact_version_diff_by_pact_version_sha"}
add ["pacts", "provider", :provider_name, "branch", :branch_name], Api::Resources::ProviderPactsForConsumerBranch, {resource_name: "branch_provider_pact_publications"}
add ["pacts", "provider", :provider_name, "branch"], Api::Resources::ProviderPactsForConsumerBranch, {resource_name: "main_branch_provider_pact_publications"}

# Verifications
add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "pact-version", :pact_version_sha, "verification-results"], Api::Resources::Verifications, {resource_name: "verification_results"}
Expand All @@ -69,6 +73,8 @@ def self.build_api(application_context = PactBroker::ApplicationContext.default_
add ["pacts", "provider", :provider_name, "tag", :tag], Api::Resources::ProviderPacts, {resource_name: "tagged_provider_pact_publications"}
add ["pacts", "provider", :provider_name, "consumer", :consumer_name, "latest-untagged"], Api::Resources::LatestPact, {resource_name: "latest_untagged_pact_publication", tag: :untagged}
add ["pacts", "provider", :provider_name, "latest"], Api::Resources::LatestProviderPacts, {resource_name: "latest_provider_pact_publications"}
add ["pacts", "provider", :provider_name, "branch", :branch_name, "latest"], Api::Resources::LatestProviderPactsForBranch, {resource_name: "latest_branch_provider_pact_publications"}
add ["pacts", "provider", :provider_name, "branch", "latest"], Api::Resources::LatestProviderPactsForBranch, {resource_name: "latest_main_branch_provider_pact_publications"}
add ["pacts", "provider", :provider_name, "latest", :tag], Api::Resources::LatestProviderPacts, {resource_name: "latest_tagged_provider_pact_publications"}
add ["pacts", "latest"], Api::Resources::LatestPacts, {resource_name: "latest_pacts"}

Expand Down
24 changes: 24 additions & 0 deletions lib/pact_broker/api/resources/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@ def links
title: "All versions of a pact for a given consumer, provider and consumer version tag",
templated: false
},
"pb:latest-branch-pact-version" =>
{
href: base_url + "/pacts/provider/{provider}/consumer/{consumer}/branch/{branch}/latest",
title: "Latest version of a pact for a given consumer, provider and consumer version branch",
templated: false
},
"pb:branch-pact-versions" =>
{
href: base_url + "/pacts/provider/{provider}/consumer/{consumer}/branch/{branch}",
title: "All versions of a pact for a given consumer, provider and consumer version branch",
templated: false
},
"pb:pacticipants" =>
{
href: base_url + "/pacticipants",
Expand All @@ -73,12 +85,24 @@ def links
title: "Latest pacts for provider with the specified tag",
templated: true
},
"pb:latest-provider-pacts-with-branch" =>
{
href: base_url + "/pacts/provider/{provider}/branch/{branch}/latest",
title: "Latest pacts for provider with the specified branch",
templated: true
},
"pb:provider-pacts-with-tag" =>
{
href: base_url + "/pacts/provider/{provider}/tag/{tag}",
title: "All pact versions for the provider with the specified consumer version tag",
templated: true
},
"pb:provider-pacts-with-branch" =>
{
href: base_url + "/pacts/provider/{provider}/branch/{branch}",
title: "All pact versions for the provider with the specified consumer version branch",
templated: true
},
"pb:provider-pacts" =>
{
href: base_url + "/pacts/provider/{provider}",
Expand Down
26 changes: 26 additions & 0 deletions lib/pact_broker/api/resources/latest_provider_pacts_for_branch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
require "pact_broker/api/resources/provider_pacts"
require "pact_broker/configuration"
require "pact_broker/api/decorators/provider_pacts_decorator"

module PactBroker
module Api
module Resources
class LatestProviderPactsForBranch < ProviderPacts
private

def pacts
pact_service.find_latest_pacts_for_provider_by_consumer_branch(
provider_name,
branch_name: identifier_from_path[:branch_name],
main_branch: identifier_from_path[:branch_name] ? false : true
)
end

def resource_title
suffix = identifier_from_path[:branch_name] ? " with consumer version branch '#{identifier_from_path[:branch_name]}'" : ""
"Latest pact versions for the provider #{identifier_from_path[:provider_name]}#{suffix}"
end
end
end
end
end
16 changes: 15 additions & 1 deletion lib/pact_broker/api/resources/pact_versions_for_branch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,27 @@ def content_types_provided
end

def allowed_methods
["DELETE", "OPTIONS"]
["GET", "DELETE", "OPTIONS"]
end

def resource_exists?
consumer && provider
end

def to_json
decorator_class(:pact_versions_decorator).new(pacts).to_json(**decorator_options(identifier_from_path))
end

def pacts
@pacts ||= pact_service.find_pacts_for_provider_and_consumer_by_consumer_branch(
provider_name,
consumer_name,
branch_name: identifier_from_path[:branch_name],
main_branch: identifier_from_path[:branch_name] ? false : true,
latest: identifier_from_path[:resource_name] == "latest_pact_publications_for_main_branch"
)
end

def delete_resource
pact_service.delete_all_pact_publications_between consumer_name, and: provider_name, branch_name: identifier_from_path[:branch_name]
set_post_deletion_response
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
require "pact_broker/api/resources/base_resource"
require "pact_broker/configuration"
require "pact_broker/api/decorators/provider_pacts_decorator"

module PactBroker
module Api
module Resources
class ProviderPactsForConsumerBranch < BaseResource

def content_types_provided
[["application/hal+json", :to_json]]
end

def allowed_methods
["GET", "OPTIONS"]
end

def resource_exists?
!!provider
end

def policy_name
:'pacts::provider_pacts'
end

def to_json
decorator_class(:provider_pacts_decorator).new(pacts).to_json(**decorator_options(identifier_from_path.merge(title: resource_title)))
end

private

def pacts
pact_service.find_pacts_for_provider_by_consumer_branch(
provider_name,
branch_name: identifier_from_path[:branch_name],
main_branch: identifier_from_path[:branch_name] ? false : true
)
end

def resource_title
suffix = identifier_from_path[:branch_name] ? " with consumer version branch '#{identifier_from_path[:branch_name]}'" : ""
"All pact versions for the provider #{identifier_from_path[:provider_name]}#{suffix}"
end
end
end
end
end
7 changes: 7 additions & 0 deletions lib/pact_broker/doc/views/index/branch-pact-versions.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Branch pact versions

Allowed methods: `GET`

Path: `/pacts/provider/{provider}/consumer/{consumer}/branch/{branch}`

Lists all the pact versions with the specified consumer, provider and consumer version branch.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Latest Branch pact versions

Allowed methods: `GET`

Path: `/pacts/provider/{provider}/consumer/{consumer}/branch/{branch}/latest`

Returns the latest pact version with the specified consumer, provider and consumer version branch.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Latest pacts for provider with the specified consumer branch

Allowed methods: `GET`

Path: `/pacts/provider/{provider}/branch/{branch}/latest`

Given a provider name and a consumer version branch name, this resource returns the latest pact for each consumer that has the specified branch.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Latest pacts for provider with the specified tag
# Latest pacts for provider with the specified consumer version tag

Allowed methods: `GET`

Path: `/pacts/provider/{provider}/latest/{tag}`

Given a provider name and a consumer version tag name, this resource returns the latest pact for each consumer that has the specified tag.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Provider pacts with consumer branch

Allowed methods: `GET`

Path: `/pacts/provider/{provider}/branch/{branch}`

Given a pacticipant name and a consumer branch, this resource returns all the pact versions for all consumers of this provider with the specified consumer branch. For most use cases, the `latest-provider-pacts-with-branch` relation will better serve consumer needs by only returning the latest pact version for specified consumer branches.
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@

Allowed methods: `GET`

Path: `/pacts/provider/{provider}/tag/{tag}`

Given a pacticipant name and a consumer version tag, this resource returns all the pact versions for all consumers of this provider with the specified tag. The most common use of this resource is to find all the `production` pact versions for the mobile consumers of an API, so that backwards compatibility can be maintained.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ def latest_for_main_branches
.remove_overridden_revisions_from_complete_query
end

def for_main_branches
consumers_join = { Sequel[:pact_publications][:consumer_id] => Sequel[:consumers][:id] }
query = self
query
.join(:pacticipants, consumers_join, { table_alias: :consumers })
.remove_overridden_revisions_from_complete_query
end

def for_currently_deployed_versions(environment_name)
deployed_versions_join = {
Sequel[:pact_publications][:consumer_version_id] => Sequel[:deployed_versions][:version_id]
Expand Down
30 changes: 30 additions & 0 deletions lib/pact_broker/pacts/repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,36 @@ def find_latest_pacts_for_provider provider_name, tag = nil
query.all.sort_by{ | p| p.consumer_name.downcase }.collect(&:to_head_pact)
end

def find_pacts_by_consumer_branch(provider_name, options = {})
consumer_name = options[:consumer]
latest = options.fetch(:latest, false)
branch = options[:branch_name]
main_branch = options.fetch(:main_branch, false)

query = scope_for(PactPublication)
.eager_for_domain_with_content
.for_provider_name(provider_name)

if consumer_name
query = query.for_consumer_name(consumer_name)
end

if main_branch
if latest
query = query.latest_for_main_branches
else
query = query.for_main_branches
end
else
if latest
query = query.latest_for_consumer_branch(branch)
else
query = query.for_branch_name(branch)
end
end
query.all.sort_by{ | p| p.consumer_name.downcase }.collect(&:to_head_pact)
end

def find_for_verification(provider_name, consumer_version_selectors)
PactsForVerificationRepository.new.find(provider_name, consumer_version_selectors)
end
Expand Down
20 changes: 20 additions & 0 deletions lib/pact_broker/pacts/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,26 @@ def find_latest_pacts_for_provider provider_name, options = {}
pact_repository.find_latest_pacts_for_provider provider_name, options[:tag]
end

def find_latest_pacts_for_provider_by_consumer_branch provider_name, options = {}
options[:latest] = true
pact_repository.find_pacts_by_consumer_branch provider_name, options
end

def find_pacts_for_provider_by_consumer_branch provider_name, options = {}
pact_repository.find_pacts_by_consumer_branch provider_name, options
end

def find_pacts_for_provider_and_consumer_by_consumer_branch provider_name, consumer, options = {}
options[:consumer] = consumer
pact_repository.find_pacts_by_consumer_branch provider_name, options
end

def find_latest_pacts_for_provider_and_consumer_by_consumer_branch provider_name, consumer, options = {}
options[:consumer] = consumer
options[:latest] = true
pact_repository.find_pacts_by_consumer_branch provider_name, options
end

def find_pact_versions_for_provider provider_name, options = {}
pact_repository.find_pact_versions_for_provider provider_name, options[:tag]
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
require "pact_broker/api/resources/latest_provider_pacts_for_branch"

module PactBroker
module Api
module Resources
describe LatestProviderPactsForBranch do
before do
allow(PactBroker::Pacts::Service).to receive(:find_latest_pacts_for_provider_by_consumer_branch).and_return(pacts)
allow(PactBroker::Api::Decorators::ProviderPactsDecorator).to receive(:new).and_return(decorator)
allow_any_instance_of(LatestProviderPactsForBranch).to receive(:resource_exists?).and_return(provider)
end

let(:provider) { double("provider") }
let(:pacts) { double("pacts") }
let(:path) { "/pacts/provider/Bar/branch/prod/latest" }
let(:decorator) { instance_double("PactBroker::Api::Decorators::ProviderPactsDecorator") }

subject { get path; last_response }

context "with a branch" do
it "finds the pacts with a branch" do
expect(PactBroker::Pacts::Service).to receive(:find_latest_pacts_for_provider_by_consumer_branch).with("Bar", branch_name: "prod", main_branch: false)
subject
end

it "sets the correct resource title" do
expect(decorator).to receive(:to_json) do | options |
expect(options[:user_options][:title]).to eq "Latest pact versions for the provider Bar with consumer version branch 'prod'"
end
subject
end
end
end
end
end
end

0 comments on commit 2d8a2dd

Please sign in to comment.