Skip to content

Commit

Permalink
feat: support creating version with branch (#371)
Browse files Browse the repository at this point in the history
* wip: allow patch to version resource

* feat: support PUT for creating version with branch and buildUrl

* chore: correct the fields that are updated when using upsert

* chore: add versions_pacticipant_id_branch_order_index

* test: manually set created_at and updated_at for upsert test

* test: upsert spec

* feat: support WIP pacts for provider branch

* refactor: clean up original wip pacts code

* refactor: verifiable pact class

* chore: set correct selectors

* chore: implement sort for Selector with branch

* feat: support provider branch in the response text for the 'pacts for verificaiton' api

* feat: include wip pacts by consumer branch

* chore: update wip pacts message for latest from branch

* refactor: add method to PactPublication to find by consumer version selector

* refactor: use PactPublication find for selector method to find pacts for verification

* chore: support branches in http test data builder

* tests: remove unncessary tests

* refactor: make code climate happier

* refactor: separate 'pacts for verification' code into separate class

* test: add tests missed in previous commit

* style: whitespace [ci-skip]

* chore: remove unused method [ci-skip]

* feat: add pb:pacticipant-version relation to index

* chore: update feature toggle experimental_no_provider_versions_makes_all_head_pacts_wip handling

* chore: update http test data builder [ci-skip]

* chore: add script to demonstrate pacticipant branches [ci-skip]

* chore: update GA test workflow
  • Loading branch information
bethesque committed Feb 3, 2021
1 parent 0d77fc2 commit 5884a04
Show file tree
Hide file tree
Showing 44 changed files with 2,037 additions and 404 deletions.
9 changes: 9 additions & 0 deletions db/migrations/20210117_add_branch_to_version.rb
@@ -0,0 +1,9 @@
Sequel.migration do
change do
alter_table(:versions) do
add_column(:branch, String)
add_column(:build_url, String)
add_index([:pacticipant_id, :branch, :order], name: "versions_pacticipant_id_branch_order_index")
end
end
end
4 changes: 2 additions & 2 deletions lib/pact_broker/api.rb
Expand Up @@ -71,10 +71,10 @@ def self.build_api(application_context = PactBroker::ApplicationContext.default_
add ['pacticipants', :pacticipant_name], Api::Resources::Pacticipant, {resource_name: "pacticipant"}
add ['pacticipants', :pacticipant_name, 'versions'], Api::Resources::Versions, {resource_name: "pacticipant_versions"}
add ['pacticipants', :pacticipant_name, 'versions', :pacticipant_version_number], Api::Resources::Version, {resource_name: "pacticipant_version"}
add ['pacticipants', :pacticipant_name, 'latest-version', :tag], Api::Resources::Version, {resource_name: "latest_tagged_pacticipant_version"}
add ['pacticipants', :pacticipant_name, 'latest-version', :tag], Api::Resources::LatestVersion, {resource_name: "latest_tagged_pacticipant_version"}
add ['pacticipants', :pacticipant_name, 'latest-version', :tag, 'can-i-deploy', 'to', :to], Api::Resources::CanIDeployPacticipantVersion, { resource_name: "can_i_deploy_latest_tagged_version" }
add ['pacticipants', :pacticipant_name, 'latest-version', :tag, 'can-i-deploy', 'to', :to, 'badge'], Api::Resources::CanIDeployBadge, { resource_name: "can_i_deploy_badge" }
add ['pacticipants', :pacticipant_name, 'latest-version'], Api::Resources::Version, {resource_name: "latest_pacticipant_version"}
add ['pacticipants', :pacticipant_name, 'latest-version'], Api::Resources::LatestVersion, {resource_name: "latest_pacticipant_version"}
add ['pacticipants', :pacticipant_name, 'versions', :pacticipant_version_number, 'tags', :tag_name], Api::Resources::Tag, {resource_name: "pacticipant_version_tag"}
add ['pacticipants', :pacticipant_name, 'labels', :label_name], Api::Resources::Label, {resource_name: "pacticipant_label"}

Expand Down
Expand Up @@ -12,9 +12,11 @@ class VerifiablePactsQueryDecorator < BaseDecorator
using PactBroker::HashRefinements

collection :provider_version_tags, default: []
property :provider_version_branch

collection :consumer_version_selectors, default: PactBroker::Pacts::Selectors.new, class: PactBroker::Pacts::Selector do
property :tag
property :branch
property :latest,
setter: ->(fragment:, represented:, **) {
represented.latest = (fragment == 'true' || fragment == true)
Expand Down
6 changes: 4 additions & 2 deletions lib/pact_broker/api/decorators/version_decorator.rb
Expand Up @@ -6,9 +6,11 @@ module Api
module Decorators
class VersionDecorator < BaseDecorator

property :number
property :number, writeable: false
property :branch
property :build_url, as: :buildUrl

collection :tags, embedded: true, :extend => PactBroker::Api::Decorators::EmbeddedTagDecorator
collection :tags, embedded: true, writeable: false, :extend => PactBroker::Api::Decorators::EmbeddedTagDecorator

include Timestamps

Expand Down
4 changes: 4 additions & 0 deletions lib/pact_broker/api/resources/default_base_resource.rb
Expand Up @@ -149,6 +149,10 @@ def consumer_version_number
identifier_from_path[:consumer_version_number]
end

def pacticipant_version_number
identifier_from_path[:pacticipant_version_number]
end

def consumer_specified?
identifier_from_path.key?(:consumer_name)
end
Expand Down
6 changes: 6 additions & 0 deletions lib/pact_broker/api/resources/index.rb
Expand Up @@ -110,6 +110,12 @@ def links
title: "Get, create or delete a tag for a pacticipant version",
templated: true
},
'pb:pacticipant-version' =>
{
href: base_url + '/pacticipants/{pacticipant}/versions/{version}',
title: "Get, create or delete a pacticipant version",
templated: true
},
'pb:metrics' =>
{
href: base_url + '/metrics',
Expand Down
27 changes: 27 additions & 0 deletions lib/pact_broker/api/resources/latest_version.rb
@@ -0,0 +1,27 @@
require 'pact_broker/api/resources/version'

module PactBroker
module Api
module Resources
class LatestVersion < Version
def content_types_accepted
[]
end

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

private

def version
if identifier_from_path[:tag]
@version ||= version_service.find_by_pacticipant_name_and_latest_tag(identifier_from_path[:pacticipant_name], identifier_from_path[:tag])
else
@version ||= version_service.find_latest_by_pacticpant_name(identifier_from_path)
end
end
end
end
end
end
Expand Up @@ -38,6 +38,7 @@ def process_post
def pacts
@pacts ||= pact_service.find_for_verification(
provider_name,
parsed_query_params.provider_version_branch,
parsed_query_params.provider_version_tags,
parsed_query_params.consumer_version_selectors,
{
Expand Down
24 changes: 15 additions & 9 deletions lib/pact_broker/api/resources/version.rb
Expand Up @@ -10,20 +10,32 @@ def content_types_provided
[["application/hal+json", :to_json]]
end

def content_types_accepted
[["application/json", :from_json]]
end

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

def resource_exists?
!!version
end

def from_json
response_code = version ? 200 : 201
parsed_version = Decorators::VersionDecorator.new(PactBroker::Domain::Version.new).from_json(request_body)
@version = version_service.create_or_update(pacticipant_name, pacticipant_version_number, parsed_version)
response.body = to_json
response_code
end

def to_json
decorator_class(:version_decorator).new(version).to_json(decorator_options)
end

def delete_resource
version_service.delete version
version_service.delete(version)
true
end

Expand All @@ -34,13 +46,7 @@ def policy_name
private

def version
if identifier_from_path[:tag]
@version ||= version_service.find_by_pacticipant_name_and_latest_tag(identifier_from_path[:pacticipant_name], identifier_from_path[:tag])
elsif identifier_from_path[:pacticipant_version_number]
@version ||= version_service.find_by_pacticipant_name_and_number(identifier_from_path)
else
@version ||= version_service.find_latest_by_pacticpant_name(identifier_from_path)
end
@version ||= version_service.find_by_pacticipant_name_and_number(identifier_from_path)
end
end
end
Expand Down
13 changes: 13 additions & 0 deletions lib/pact_broker/doc/views/index/pacticipant-version.markdown
@@ -0,0 +1,13 @@
# Pacticipant version

Allowed methods: `GET`, `PUT`, `DELETE`

Path: `/pacticipants/{pacticipant}/versions/{version}`

## Example

PUT http://broker/pacticipants/Bar/versions/1e70030c6579915e5ff56b107a0fd25cf5df7464
{
"branch": "main",
"buildUrl": "http://ci.mydomain/my-job/1"
}
8 changes: 8 additions & 0 deletions lib/pact_broker/domain/pacticipant.rb
Expand Up @@ -27,6 +27,10 @@ def label label_name
filter = name_like(Sequel[:labels][:name], label_name)
join(:labels, {pacticipant_id: :id}).where(filter)
end

def find_by_name(name)
where(name_like(:name, name))
end
end

def before_destroy
Expand All @@ -51,6 +55,10 @@ def validate
messages << message('errors.validation.attribute_missing', attribute: 'name') unless name
messages
end

def any_versions?
PactBroker::Domain::Version.where(pacticipant: self).any?
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/pact_broker/domain/version.rb
Expand Up @@ -22,7 +22,7 @@ def latest?

class Version < Sequel::Model
plugin :timestamps, update_on_create: true
plugin :insert_ignore, identifying_columns: [:pacticipant_id, :number]
plugin :upsert, identifying_columns: [:pacticipant_id, :number]

set_primary_key :id
one_to_many :pact_publications, order: :revision_number, class: "PactBroker::Pacts::PactPublication", key: :consumer_version_id
Expand Down
81 changes: 2 additions & 79 deletions lib/pact_broker/pacts/pact_publication.rb
Expand Up @@ -4,6 +4,7 @@
require 'pact_broker/repositories/helpers'
require 'pact_broker/integrations/integration'
require 'pact_broker/tags/head_pact_tags'
require 'pact_broker/pacts/pact_publication_dataset_module'

module PactBroker
module Pacts
Expand All @@ -27,86 +28,8 @@ class PactPublication < Sequel::Model(:pact_publications)

dataset_module do
include PactBroker::Repositories::Helpers
include PactPublicationDatasetModule

def remove_overridden_revisions
join(:latest_pact_publication_ids_for_consumer_versions, { Sequel[:lp][:pact_publication_id] => Sequel[:pact_publications][:id] }, { table_alias: :lp})
end

def join_consumer_versions(table_alias = :cv)
join(:versions, { Sequel[:pact_publications][:consumer_version_id] => Sequel[table_alias][:id] }, { table_alias: table_alias })
end

def join_consumer_version_tags(table_alias = :ct)
join(:tags, { Sequel[table_alias][:version_id] => Sequel[:pact_publications][:consumer_version_id]}, { table_alias: table_alias })
end

def join_consumer_version_tags_with_names(consumer_version_tag_names)
join(:tags, {
Sequel[:ct][:version_id] => Sequel[:pact_publications][:consumer_version_id],
Sequel[:ct][:name] => consumer_version_tag_names
}, {
table_alias: :ct
})
end

def join_providers(table_alias = :providers)
join(:pacticipants, { Sequel[:pact_publications][:provider_id] => Sequel[table_alias][:id] }, { table_alias: table_alias })
end

def join_consumers(table_alias = :consumers)
join(:pacticipants, { Sequel[:pact_publications][:consumer_id] => Sequel[table_alias][:id] }, { table_alias: table_alias })
end

def join_pact_versions
join(:pact_versions, { Sequel[:pact_publications][:pact_version_id] => Sequel[:pact_versions][:id] })
end

def eager_load_pact_versions
eager(:pact_versions)
end

def tag tag_name
filter = name_like(Sequel.qualify(:tags, :name), tag_name)
join(:tags, {version_id: :consumer_version_id}).where(filter)
end

def provider_name_like(name)
where(name_like(Sequel[:providers][:name], name))
end

def consumer_name_like(name)
where(name_like(Sequel[:consumers][:name], name))
end

def consumer_version_number_like(number)
where(name_like(Sequel[:cv][:number], number))
end

def consumer_version_tag(tag)
where(Sequel[:ct][:name] => tag)
end

def order_by_consumer_name
order_append_ignore_case(Sequel[:consumers][:name])
end

def order_by_consumer_version_order
order_append(Sequel[:cv][:order])
end

def where_consumer_if_set(consumer)
if consumer
where(consumer: consumer)
else
self
end
end

def delete
require 'pact_broker/webhooks/triggered_webhook'
PactBroker::Webhooks::TriggeredWebhook.where(pact_publication: self).delete
super
end
end

def before_create
Expand Down

0 comments on commit 5884a04

Please sign in to comment.