Skip to content

Commit

Permalink
feat: add endpoint to create pacts, pacticipant, version, tags in one…
Browse files Browse the repository at this point in the history
… request (#420)
  • Loading branch information
bethesque authored Apr 27, 2021
1 parent 7524708 commit df899eb
Show file tree
Hide file tree
Showing 57 changed files with 1,806 additions and 75 deletions.
5 changes: 4 additions & 1 deletion lib/pact_broker/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ def self.build_api(application_context = PactBroker::ApplicationContext.default_

add ['webhooks', 'execute' ], Api::Resources::WebhookExecution, {resource_name: "execute_unsaved_webhook"}
add ['webhooks', :uuid ], Api::Resources::Webhook, {resource_name: "webhook"}
add ['webhooks', :uuid, 'trigger', :trigger_uuid, 'logs' ], Api::Resources::TriggeredWebhookLogs, {resource_name: "triggered_webhook_logs"}
add ['webhooks', :uuid, 'trigger', :trigger_uuid, 'logs' ], Api::Resources::TriggeredWebhookLogs, { resource_name: "triggered_webhook_logs" }
add ['triggered-webhooks', :trigger_uuid, 'logs' ], Api::Resources::TriggeredWebhookLogs, { resource_name: "triggered_webhook_logs" }
add ['webhooks', :uuid, 'execute' ], Api::Resources::WebhookExecution, {resource_name: "execute_webhook"}
add ['webhooks'], Api::Resources::AllWebhooks, {resource_name: "webhooks"}

Expand All @@ -115,6 +116,8 @@ def self.build_api(application_context = PactBroker::ApplicationContext.default_
add ['dashboard', 'provider', :provider_name, 'consumer', :consumer_name ], Api::Resources::Dashboard, {resource_name: "integration_dashboard"}
add ['test','error'], Api::Resources::ErrorTest, {resource_name: "error_test"}

add ['contracts', 'publish'], Api::Resources::PublishContracts, { resource_name: "publish_contracts" }

if PactBroker.feature_enabled?(:environments)
add ['environments'], Api::Resources::Environments, { resource_name: "environments" }
add ['environments', :environment_uuid], Api::Resources::Environment, { resource_name: "environment" }
Expand Down
4 changes: 4 additions & 0 deletions lib/pact_broker/api/contracts/dry_validation_predicates.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ module DryValidationPredicates
DateTime.parse(value) rescue false
end

predicate(:base64?) do |value|
Base64.strict_decode64(value) rescue false
end

predicate(:not_blank?) do | value |
value && value.is_a?(String) && value.strip.size > 0
end
Expand Down
104 changes: 104 additions & 0 deletions lib/pact_broker/api/contracts/publish_contracts_schema.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
require 'dry-validation'
require 'pact_broker/api/contracts/dry_validation_workarounds'
require 'pact_broker/api/contracts/dry_validation_predicates'
require 'pact_broker/messages'

module PactBroker
module Api
module Contracts
class PublishContractsSchema
extend DryValidationWorkarounds
using PactBroker::HashRefinements
extend PactBroker::Messages

SCHEMA = Dry::Validation.Schema do
configure do
predicates(DryValidationPredicates)
config.messages_file = File.expand_path("../../../locale/en.yml", __FILE__)
end

required(:pacticipantName).filled(:str?, :not_blank?)
required(:pacticipantVersionNumber).filled(:not_blank?, :single_line?)
optional(:tags).each(:not_blank?, :single_line?)
optional(:branch).maybe(:not_blank?, :single_line?)
optional(:buildUrl).maybe(:single_line?)

required(:contracts).each do
required(:consumerName).filled(:str?, :not_blank?)
required(:providerName).filled(:str?, :not_blank?)
required(:content).filled(:str?)
required(:contentType).filled(included_in?: ["application/json"])
required(:specification).filled(included_in?: ["pact"])
optional(:writeMode).filled(included_in?:["overwrite", "merge"])
end
end

def self.call(params)
select_first_message(
flatten_indexed_messages(
add_cross_field_validation_errors(
params&.symbolize_keys,
SCHEMA.call(params&.symbolize_keys).messages(full: true)
)
)
)
end

def self.add_cross_field_validation_errors(params, errors)
if params[:contracts].is_a?(Array)
params[:contracts].each_with_index do | contract, i |
if contract.is_a?(Hash)
validate_consumer_name(params, contract, i, errors)
validate_consumer_name_in_content(params, contract, i, errors)
validate_provider_name_in_content(contract, i, errors)
validate_encoding(contract, i, errors)
validate_content_matches_content_type(contract, i, errors)
end
end
end
errors
end

def self.validate_consumer_name(params, contract, i, errors)
if params[:pacticipantName] && contract[:consumerName] && (contract[:consumerName] != params[:pacticipantName])
add_contract_error(validation_message('consumer_name_in_contract_mismatch_pacticipant_name', { consumer_name_in_contract: contract[:consumerName], pacticipant_name: params[:pacticipantName] } ), i, errors)
end
end

def self.validate_consumer_name_in_content(params, contract, i, errors)
consumer_name_in_content = contract.dig(:decodedParsedContent, :consumer, :name)
if consumer_name_in_content && consumer_name_in_content != params[:pacticipantName]
add_contract_error(validation_message('consumer_name_in_content_mismatch_pacticipant_name', { consumer_name_in_content: consumer_name_in_content, pacticipant_name: params[:pacticipantName] } ), i, errors)
end
end

def self.validate_provider_name_in_content(contract, i, errors)
provider_name_in_content = contract.dig(:decodedParsedContent, :provider, :name)
if provider_name_in_content && provider_name_in_content != contract[:providerName]
add_contract_error(validation_message('provider_name_in_content_mismatch', { provider_name_in_content: provider_name_in_content, provider_name: contract[:providerName] } ), i, errors)
end
end

def self.validate_encoding(contract, i, errors)
if contract[:decodedContent].nil?
add_contract_error(message('errors.base64?', scope: nil), i, errors)
end
end

def self.validate_content_matches_content_type(contract, i, errors)
if contract[:decodedParsedContent].nil? && contract[:contentType]
add_contract_error(validation_message('invalid_content_for_content_type', { content_type: contract[:contentType]}), i, errors)
end
end


def self.add_contract_error(message, i, errors)
errors[:contracts] ||= {}
errors[:contracts][i] ||= []
errors[:contracts][i] << message
errors
end
end
end
end
end
6 changes: 5 additions & 1 deletion lib/pact_broker/api/decorators/base_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ class BaseDecorator < Roar::Decorator
include FormatDateTime
using PactBroker::StringRefinements

def self.camelize_property_names
@camelize = true
end

def self.property(name, options={}, &block)
if options.delete(:camelize)
if options.delete(:camelize) || @camelize
camelized_name = name.to_s.camelcase(false).to_sym
super(name, { as: camelized_name }.merge(options), &block)
else
Expand Down
17 changes: 17 additions & 0 deletions lib/pact_broker/api/decorators/embedded_pacticipant_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
require_relative 'base_decorator'

module PactBroker
module Api
module Decorators
class EmbeddedPacticipantDecorator < BaseDecorator
camelize_property_names

property :name

link :self do | options |
pacticipant_url(options[:base_url], represented)
end
end
end
end
end
2 changes: 2 additions & 0 deletions lib/pact_broker/api/decorators/embedded_version_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ module PactBroker
module Api
module Decorators
class EmbeddedVersionDecorator < BaseDecorator
camelize_property_names

property :number
property :branch
property :build_url

link :self do | options |
{
Expand Down
12 changes: 7 additions & 5 deletions lib/pact_broker/api/decorators/pacticipant_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ module PactBroker
module Api
module Decorators
class PacticipantDecorator < BaseDecorator
camelize_property_names

property :name
property :display_name, camelize: true
property :repository_url, camelize: true
property :repository_name, camelize: true
property :repository_namespace, camelize: true
property :main_development_branches, camelize: true
property :display_name
property :repository_url
property :repository_name
property :repository_namespace
property :main_development_branches

property :latest_version, as: :latestVersion, :class => PactBroker::Domain::Version, extend: PactBroker::Api::Decorators::EmbeddedVersionDecorator, embedded: true, writeable: false
collection :labels, :class => PactBroker::Domain::Label, extend: PactBroker::Api::Decorators::EmbeddedLabelDecorator, embedded: true
Expand Down
19 changes: 19 additions & 0 deletions lib/pact_broker/api/decorators/publish_contract_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
require 'pact_broker/api/decorators/base_decorator'
require 'pact_broker/api/decorators/timestamps'

module PactBroker
module Api
module Decorators
class PublishContractDecorator < BaseDecorator
camelize_property_names

property :consumer_name
property :provider_name
property :specification
property :content_type
property :decoded_content
property :write_mode, default: "overwrite"
end
end
end
end
21 changes: 21 additions & 0 deletions lib/pact_broker/api/decorators/publish_contracts_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
require 'pact_broker/api/decorators/base_decorator'
require 'pact_broker/api/decorators/publish_contract_decorator'
require 'pact_broker/contracts/contract_to_publish'

module PactBroker
module Api
module Decorators
class PublishContractsDecorator < BaseDecorator
camelize_property_names

property :pacticipant_name
property :pacticipant_version_number
property :tags
property :branch
property :build_url

collection :contracts, :extend => PublishContractDecorator, class: PactBroker::Contracts::ContractToPublish
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
require 'pact_broker/api/decorators/base_decorator'
require 'pact_broker/api/decorators/publish_contract_decorator'
require 'pact_broker/api/decorators/embedded_version_decorator'

module PactBroker
module Api
module Decorators
class PublishContractsResultsDecorator < BaseDecorator
camelize_property_names

property :logs, getter: ->(represented:, **) { represented.logs.collect(&:to_h) }

property :pacticipant, embedded: true, extend: EmbeddedPacticipantDecorator
property :version, embedded: true, extend: EmbeddedVersionDecorator

link :'pb:pacticipant' do | options |
{
title: "Pacticipant",
name: represented.pacticipant.name,
href: pacticipant_url(options.fetch(:base_url), represented.pacticipant)
}
end

link :'pb:pacticipant-version' do | options |
{
title: "Pacticipant version",
name: represented.version.number,
href: version_url(options.fetch(:base_url), represented.version)
}
end

links :'pb:pacticipant-version-tags' do | options |
represented.tags.collect do | tag |
{
title: "Tag",
name: tag.name,
href: tag_url(options.fetch(:base_url), tag)
}
end
end

links :'pb:contracts' do | options |
represented.contracts.collect do | contract |
{
title: 'Pact',
name: contract.name,
href: pact_url(options.fetch(:base_url), contract)
}
end
end
end
end
end
end
2 changes: 1 addition & 1 deletion lib/pact_broker/api/pact_broker_urls.rb
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ def pact_triggered_webhooks_url pact, base_url = ''
end

def triggered_webhook_logs_url triggered_webhook, base_url
"#{base_url}/webhooks/#{triggered_webhook.webhook_uuid}/trigger/#{triggered_webhook.trigger_uuid}/logs"
"#{base_url}/triggered-webhooks/#{triggered_webhook.trigger_uuid}/logs"
end

def badge_url_for_latest_pact pact, base_url = ''
Expand Down
5 changes: 5 additions & 0 deletions lib/pact_broker/api/resources/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ def links
title: 'Publish a pact',
templated: true
},
'pb:publish-contracts' => {
href: base_url + '/contracts/publish',
title: 'Publish contracts',
templated: false
},
'pb:latest-pact-versions' =>
{
href: base_url + '/pacts/latest',
Expand Down
4 changes: 0 additions & 4 deletions lib/pact_broker/api/resources/pact.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,6 @@ def policy_pacticipant
def pact
@pact ||= pact_service.find_pact(pact_params)
end

def pact_params
@pact_params ||= PactBroker::Pacts::PactParams.from_request request, path_info
end
end
end
end
Expand Down
Loading

0 comments on commit df899eb

Please sign in to comment.