Skip to content

Commit

Permalink
feat: use the pb:publish-contracts relation and endpoint to publish p…
Browse files Browse the repository at this point in the history
…acts
  • Loading branch information
bethesque committed Apr 26, 2021
1 parent 7ee7424 commit 19f1b0b
Show file tree
Hide file tree
Showing 14 changed files with 482 additions and 79 deletions.
100 changes: 100 additions & 0 deletions doc/pacts/markdown/Pact Broker Client - Pact Broker.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@

* [A request for the index resource](#a_request_for_the_index_resource_given_the_pb:pacticipant-version_relation_exists_in_the_index_resource) given the pb:pacticipant-version relation exists in the index resource

* [A request for the index resource](#a_request_for_the_index_resource_given_the_pb:publish-contracts_relations_exists_in_the_index_resource) given the pb:publish-contracts relations exists in the index resource

* [A request for the index resource with the webhook relation](#a_request_for_the_index_resource_with_the_webhook_relation)

* [A request for the list of the latest pacts from all consumers for the Pricing Service'](#a_request_for_the_list_of_the_latest_pacts_from_all_consumers_for_the_Pricing_Service'_given_a_latest_pact_between_Condor_and_the_Pricing_Service_exists) given a latest pact between Condor and the Pricing Service exists
Expand Down Expand Up @@ -92,6 +94,8 @@

* [A request to publish a pact with method put](#a_request_to_publish_a_pact_with_method_put_given_the_'Pricing_Service'_and_'Condor'_already_exist_in_the_pact-broker,_and_Condor_already_has_a_pact_published_for_version_1.3.0) given the 'Pricing Service' and 'Condor' already exist in the pact-broker, and Condor already has a pact published for version 1.3.0

* [A request to publish contracts](#a_request_to_publish_contracts)

* [A request to record a deployment](#a_request_to_record_a_deployment_given_version_5556b8149bf8bac76bc30f50a8a2dd4c22c85f30_of_pacticipant_Foo_exists_with_a_test_environment_available_for_deployment) given version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment

* [A request to register the repository URL of a pacticipant](#a_request_to_register_the_repository_URL_of_a_pacticipant_given_the_'Pricing_Service'_already_exists_in_the_pact-broker) given the 'Pricing Service' already exists in the pact-broker
Expand Down Expand Up @@ -832,6 +836,33 @@ Pact Broker will respond with:
}
}
```
<a name="a_request_for_the_index_resource_given_the_pb:publish-contracts_relations_exists_in_the_index_resource"></a>
Given **the pb:publish-contracts relations exists in the index resource**, upon receiving **a request for the index resource** from Pact Broker Client, with
```json
{
"method": "GET",
"path": "/",
"headers": {
"Accept": "application/hal+json"
}
}
```
Pact Broker will respond with:
```json
{
"status": 200,
"headers": {
"Content-Type": "application/hal+json;charset=utf-8"
},
"body": {
"_links": {
"pb:publish-contracts": {
"href": "http://localhost:1234/HAL-REL-PLACEHOLDER-PB-PUBLISH-CONTRACTS"
}
}
}
}
```
<a name="a_request_for_the_index_resource_with_the_webhook_relation"></a>
Upon receiving **a request for the index resource with the webhook relation** from Pact Broker Client, with
```json
Expand Down Expand Up @@ -1928,6 +1959,75 @@ Pact Broker will respond with:
}
}
```
<a name="a_request_to_publish_contracts"></a>
Upon receiving **a request to publish contracts** from Pact Broker Client, with
```json
{
"method": "POST",
"path": "/HAL-REL-PLACEHOLDER-PB-PUBLISH-CONTRACTS",
"headers": {
"Content-Type": "application/json",
"Accept": "application/hal+json"
},
"body": {
"pacticipantName": "Foo",
"pacticipantVersionNumber": "5556b8149bf8bac76bc30f50a8a2dd4c22c85f30",
"branch": "main",
"tags": [
"dev"
],
"buildUrl": "http://build",
"contracts": [
{
"consumerName": "Foo",
"providerName": "Bar",
"specification": "pact",
"contentType": "application/json",
"content": "eyJjb25zdW1lciI6eyJuYW1lIjoiRm9vIn0sInByb3ZpZGVyIjp7Im5hbWUiOiJCYXIifSwiaW50ZXJhY3Rpb25zIjpbeyJkZXNjcmlwdGlvbiI6ImFuIGV4YW1wbGUgcmVxdWVzdCIsInByb3ZpZGVyU3RhdGUiOiJhIHByb3ZpZGVyIHN0YXRlIiwicmVxdWVzdCI6eyJtZXRob2QiOiJHRVQiLCJwYXRoIjoiLyIsImhlYWRlcnMiOnt9fSwicmVzcG9uc2UiOnsic3RhdHVzIjoyMDAsImhlYWRlcnMiOnsiQ29udGVudC1UeXBlIjoiYXBwbGljYXRpb24vaGFsK2pzb24ifX19XSwibWV0YWRhdGEiOnsicGFjdFNwZWNpZmljYXRpb24iOnsidmVyc2lvbiI6IjIuMC4wIn19fQ==",
"writeMode": "overwrite"
}
]
}
}
```
Pact Broker will respond with:
```json
{
"status": 200,
"headers": {
"Content-Type": "application/hal+json;charset=utf-8"
},
"body": {
"_embedded": {
"pacticipant": {
"name": "Foo"
},
"version": {
"number": "5556b8149bf8bac76bc30f50a8a2dd4c22c85f30",
"buildUrl": "http://build"
}
},
"logs": [
{
"level": "info",
"message": "some message"
}
],
"_links": {
"pb:pacticipant-version-tags": [
{
"name": "dev"
}
],
"pb:contracts": [
{
"href": "http://some-pact"
}
]
}
}
}
```
<a name="a_request_to_record_a_deployment_given_version_5556b8149bf8bac76bc30f50a8a2dd4c22c85f30_of_pacticipant_Foo_exists_with_a_test_environment_available_for_deployment"></a>
Given **version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment**, upon receiving **a request to record a deployment** from Pact Broker Client, with
```json
Expand Down
3 changes: 2 additions & 1 deletion lib/pact_broker/client/cli/broker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def can_i_deploy(*ignored_but_necessary)
method_option :tag_with_git_branch, aliases: "-g", type: :boolean, default: false, required: false, desc: "Tag consumer version with the name of the current git branch. Default: false"
method_option :build_url, desc: "The build URL that created the pact"
method_option :merge, type: :boolean, default: false, require: false, desc: "If a pact already exists for this consumer version and provider, merge the contents. Useful when running Pact tests concurrently on different build nodes."
method_option :output, aliases: "-o", desc: "json or text", default: 'text'
shared_authentication_options

def publish(*pact_files)
Expand Down Expand Up @@ -284,6 +285,7 @@ def publish_pacts pact_files
options.broker_base_url,
file_list(pact_files),
consumer_version_params,
{ merge: options[:merge], output: options.output }.compact,
pact_broker_client_options.merge(write_options)
)
end
Expand Down Expand Up @@ -381,7 +383,6 @@ def parse_webhook_options(webhook_url)
provider: options.provider,
events: events
}

end

def run_webhook_commands webhook_url
Expand Down
8 changes: 6 additions & 2 deletions lib/pact_broker/client/hal/http_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def create_request uri, http_method, body = nil, headers = {}
end

def perform_request request, uri
response = until_truthy_or_max_times(times: 5, sleep: 5, condition: ->(resp) { resp.code.to_i < 500 }) do
response = until_truthy_or_max_times(condition: ->(resp) { resp.code.to_i < 500 }) do
http = Net::HTTP.new(uri.host, uri.port, :ENV)
http.set_debug_output(output_stream) if verbose
http.use_ssl = (uri.scheme == 'https')
Expand All @@ -71,7 +71,7 @@ def perform_request request, uri
end

def until_truthy_or_max_times options = {}
max_tries = options.fetch(:times, 3)
max_tries = options.fetch(:times, default_max_tries)
tries = 0
sleep_interval = options.fetch(:sleep, 5)
sleep(sleep_interval) if options[:sleep_first]
Expand All @@ -97,6 +97,10 @@ def until_truthy_or_max_times options = {}
end
end

def default_max_tries
5
end

def sleep seconds
Kernel.sleep seconds
end
Expand Down
1 change: 0 additions & 1 deletion lib/pact_broker/client/pacts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
module PactBroker
module Client
class Pacts < BaseClient

def publish options
consumer_version = options[:consumer_version]
pact_hash = options[:pact_hash]
Expand Down
47 changes: 31 additions & 16 deletions lib/pact_broker/client/publish_pacts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,19 @@ class PublishPacts
using PactBroker::Client::HashRefinements
include HalClientMethods

def self.call(pact_broker_base_url, pact_file_paths, consumer_version_params, pact_broker_client_options={})
new(pact_broker_base_url, pact_file_paths, consumer_version_params, pact_broker_client_options).call
def self.call(pact_broker_base_url, pact_file_paths, consumer_version_params, options, pact_broker_client_options={})
new(pact_broker_base_url, pact_file_paths, consumer_version_params, options, pact_broker_client_options).call
end

def initialize pact_broker_base_url, pact_file_paths, consumer_version_params, pact_broker_client_options={}
def initialize pact_broker_base_url, pact_file_paths, consumer_version_params, options, pact_broker_client_options={}
@pact_broker_base_url = pact_broker_base_url
@pact_file_paths = pact_file_paths
@consumer_version_params = consumer_version_params
@consumer_version_number = consumer_version_params[:number].respond_to?(:strip) ? consumer_version_params[:number].strip : consumer_version_params[:number]
@branch = consumer_version_params[:branch]
@build_url = consumer_version_params[:build_url]
@branch = consumer_version_params[:branch]&.strip
@build_url = consumer_version_params[:build_url]&.strip
@tags = consumer_version_params[:tags] ? consumer_version_params[:tags].collect{ |tag| tag.respond_to?(:strip) ? tag.strip : tag } : []
@version_required = consumer_version_params[:version_required]
@options = options
@pact_broker_client_options = pact_broker_client_options
end

Expand All @@ -30,18 +31,18 @@ def call
publish_pacts
PactBroker::Client::CommandResult.new(success?, message)
else
PublishPactsTheOldWay.call(pact_broker_base_url, pact_file_paths, consumer_version_params, pact_broker_client_options)
PublishPactsTheOldWay.call(pact_broker_base_url, pact_file_paths, consumer_version_params, options, pact_broker_client_options)
end
end

private

attr_reader :pact_broker_base_url, :pact_file_paths, :consumer_version_number, :branch, :tags, :build_url, :pact_broker_client_options, :response_entities
attr_reader :pact_broker_base_url, :pact_file_paths, :consumer_version_params, :consumer_version_number, :branch, :tags, :build_url, :options, :pact_broker_client_options, :response_entities

def request_body_for(consumer_name)
{
pacticipantName: consumer_name,
versionNumber: consumer_version_number,
pacticipantVersionNumber: consumer_version_number,
tags: tags,
branch: branch,
buildUrl: build_url,
Expand All @@ -60,10 +61,22 @@ def success?
end

def message
if options[:output] == "json"
response_entities.collect(&:response).collect(&:body).to_a.to_json
else
text_message
end
end

def text_message
response_entities.flat_map do | response_entity |
if response_entity.success?
response_entity.logs.collect do | log |
colorized_message(log)
if response_entity.logs
response_entity.logs.collect do | log |
colorized_message(log)
end
else
"Successfully published pacts"
end
else
::Term::ANSIColor.red(response_entity.response.body.to_s)
Expand All @@ -90,18 +103,16 @@ def color_for_level(level)
end

def contracts_for(consumer_name)
pact_files_for(consumer_name).collect do | pact_file |
end

pact_files_for(consumer_name).group_by(&:pact_name).values.collect do | pact_files |
$stderr.puts "Merging #{pact_files.collect(&:path).join(", ")}" if pact_files.size > 1
pact_hash = PactHash[merge_contents(pact_files)]
{
role: "consumer",
consumerName: pact_hash.consumer_name,
providerName: pact_hash.provider_name,
specification: "pact",
contentType: "application/json",
content: Base64.strict_encode64(pact_hash.to_json)
content: Base64.strict_encode64(pact_hash.to_json),
writeMode: write_mode
}
end
end
Expand All @@ -122,6 +133,10 @@ def consumer_names
pact_files.collect(&:consumer_name).uniq
end

def write_mode
options[:merge] ? "merge" : "overwrite"
end

def validate
raise PactBroker::Client::Error.new("Please specify the consumer_version_number") unless (consumer_version_number && consumer_version_number.to_s.strip.size > 0)
raise PactBroker::Client::Error.new("Please specify the pact_broker_base_url") unless (pact_broker_base_url && pact_broker_base_url.to_s.strip.size > 0)
Expand Down
6 changes: 3 additions & 3 deletions lib/pact_broker/client/publish_pacts_the_old_way.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ class PublishPactsTheOldWay
using PactBroker::Client::HashRefinements
include HalClientMethods

def self.call(pact_broker_base_url, pact_file_paths, consumer_version_params, pact_broker_client_options={})
new(pact_broker_base_url, pact_file_paths, consumer_version_params, pact_broker_client_options).call
def self.call(pact_broker_base_url, pact_file_paths, consumer_version_params, options, pact_broker_client_options={})
new(pact_broker_base_url, pact_file_paths, consumer_version_params, options, pact_broker_client_options).call
end

def initialize pact_broker_base_url, pact_file_paths, consumer_version_params, pact_broker_client_options={}
def initialize pact_broker_base_url, pact_file_paths, consumer_version_params, options, pact_broker_client_options={}
@pact_broker_base_url = pact_broker_base_url
@pact_file_paths = pact_file_paths
@consumer_version_number = consumer_version_params[:number].respond_to?(:strip) ? consumer_version_params[:number].strip : consumer_version_params[:number]
Expand Down
8 changes: 4 additions & 4 deletions lib/pact_broker/client/tasks/publication_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,14 @@ def rake_task &block
desc "Publish pacts to pact broker"
task task_name do
block.call(self)
require 'pact_broker/client/publish_pacts_the_old_way'
require 'pact_broker/client/publish_pacts'
pact_broker_client_options = { write: write_method, token: pact_broker_token }
pact_broker_client_options[:basic_auth] = pact_broker_basic_auth if pact_broker_basic_auth && pact_broker_basic_auth.any?
pact_broker_client_options.compact!
consumer_version_params = { number: consumer_version, branch: the_branch, build_url: build_url, tags: all_tags, version_required: version_required }.compact
success = PactBroker::Client::PublishPactsTheOldWay.new(pact_broker_base_url, FileList[pattern], consumer_version_params, pact_broker_client_options).call
raise "One or more pacts failed to be published" unless success
result = PactBroker::Client::PublishPacts.new(pact_broker_base_url, FileList[pattern], consumer_version_params, {}, pact_broker_client_options).call
$stdout.puts result.message
raise "One or more pacts failed to be published" unless result.success
end
end
end
Expand All @@ -86,7 +87,6 @@ def the_branch
branch
end
end

end
end
end
18 changes: 15 additions & 3 deletions script/publish-pact.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
bundle exec bin/pact-broker publish spec/pacts/pact_broker_client-pact_broker.json \
--consumer-app-version 1.2.7 \
# bundle exec bin/pact-broker create-or-update-webhook http://localhost:9393 \
# --uuid d40f38c3-aaa3-47f5-9161-95c07bc16b14 \
# --request POST \
# --description "foo webhook" \
# --contract-published

bundle exec bin/pact-broker create-or-update-webhook http://localhost:9393 \
--uuid d40f38c3-aaa3-47f5-9161-95c07bc16555 \
--provider Bar \
--request POST \
--contract-published

bundle exec bin/pact-broker publish spec/pacts/pact_broker_client-pact_broker.json spec/pacts/foo-bar.json \
--consumer-app-version 1.2.12 \
--broker-base-url http://localhost:9292 \
--broker-username localhost --broker-password localhost \
--auto-detect-version-properties \
--build-url http://mybuild \
--branch master
--branch master --tag foo5

31 changes: 31 additions & 0 deletions spec/fixtures/foo-bar.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"consumer": {
"name": "Foo"
},
"provider": {
"name": "Bar"
},
"interactions": [
{
"description": "an example request",
"providerState": "a provider state",
"request": {
"method": "GET",
"path": "/",
"headers": {
}
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/hal+json"
}
}
}
],
"metadata": {
"pactSpecification": {
"version": "2.0.0"
}
}
}
Loading

0 comments on commit 19f1b0b

Please sign in to comment.