Skip to content

Commit

Permalink
feat: add create-webhook to CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
bethesque committed Jun 13, 2018
1 parent 9d4bb31 commit e1ec885
Show file tree
Hide file tree
Showing 11 changed files with 882 additions and 1 deletion.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,32 @@ Description:
```

### create-webhook

```
Usage:
pact-broker create-webhook URL --consumer=CONSUMER --provider=PROVIDER -X, --request=REQUEST -b, --broker-base-url=BROKER_BASE_URL
Options:
-X, --request=REQUEST # HTTP method
-H, [--header=one two three] # Header
-d, [--data=DATA] # Data
-u, [--user=USER] # Basic auth username and password eg. username:password
--consumer=CONSUMER # Consumer name
--provider=PROVIDER # Provider name
-b, --broker-base-url=BROKER_BASE_URL # The base URL of the Pact Broker
-u, [--broker-username=BROKER_USERNAME] # Pact Broker basic auth username
-p, [--broker-password=BROKER_PASSWORD] # Pact Broker basic auth password
[--contract-content-changed], [--no-contract-content-changed] # Trigger this webhook when the pact content changes
[--provider-verification-published], [--no-provider-verification-published] # Trigger this webhook when a provider verification result is published
-v, [--verbose], [--no-verbose] # Verbose output. Default: false
Description:
Create a curl command that executes the request that you want your webhook to execute, then replace "curl" with "pact-broker
create-webhook" and add the consumer, provider, event types and broker details. Note that the URL must be the first parameter
when executing create-webhook.
```

## Usage - Ruby

### Consumer
Expand Down
193 changes: 193 additions & 0 deletions doc/pacts/markdown/Pact Broker Client - Pact Broker.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@

* [A request retrieve a pact for a specific version](#a_request_retrieve_a_pact_for_a_specific_version_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 create a webhook for a consumer and provider](#a_request_to_create_a_webhook_for_a_consumer_and_provider_given_'Condor'_does_not_exist_in_the_pact-broker) given 'Condor' does not exist in the pact-broker

* [A request to create a webhook with a JSON body for a consumer and provider](#a_request_to_create_a_webhook_with_a_JSON_body_for_a_consumer_and_provider_given_the_'Pricing_Service'_and_'Condor'_already_exist_in_the_pact-broker) given the 'Pricing Service' and 'Condor' already exist in the pact-broker

* [A request to create a webhook with a non-JSON body for a consumer and provider](#a_request_to_create_a_webhook_with_a_non-JSON_body_for_a_consumer_and_provider_given_the_'Pricing_Service'_and_'Condor'_already_exist_in_the_pact-broker) given the 'Pricing Service' and 'Condor' already exist in the pact-broker

* [A request to get the Pricing Service](#a_request_to_get_the_Pricing_Service_given_the_'Pricing_Service'_already_exists_in_the_pact-broker) given the 'Pricing Service' already exists in the pact-broker

* [A request to get the Pricing Service](#a_request_to_get_the_Pricing_Service_given_the_'Pricing_Service'_does_not_exist_in_the_pact-broker) given the 'Pricing Service' does not exist in the pact-broker
Expand Down Expand Up @@ -70,6 +76,8 @@

* [A request to tag the production version of Condor](#a_request_to_tag_the_production_version_of_Condor_given_'Condor'_exists_in_the_pact-broker) given 'Condor' exists in the pact-broker

* [An invalid request to create a webhook for a consumer and provider](#an_invalid_request_to_create_a_webhook_for_a_consumer_and_provider_given_the_'Pricing_Service'_and_'Condor'_already_exist_in_the_pact-broker) given the 'Pricing Service' and 'Condor' already exist in the pact-broker

#### Interactions

<a name="a_request_for_the_compatibility_matrix_for_a_pacticipant_that_does_not_exist"></a>
Expand Down Expand Up @@ -640,6 +648,143 @@ Pact Broker will respond with:
}
}
```
<a name="a_request_to_create_a_webhook_for_a_consumer_and_provider_given_&#39;Condor&#39;_does_not_exist_in_the_pact-broker"></a>
Given **'Condor' does not exist in the pact-broker**, upon receiving **a request to create a webhook for a consumer and provider** from Pact Broker Client, with
```json
{
"method": "post",
"path": "/webhooks/provider/Pricing%20Service/consumer/Condor",
"headers": {
"Content-Type": "application/json",
"Accept": "application/hal+json"
},
"body": {
"events": [
{
"name": "contract_content_changed"
}
],
"request": {
"url": "https://webhook",
"method": "POST",
"headers": {
"Foo": "bar",
"Bar": "foo"
},
"body": {
"some": "body"
},
"username": "username",
"password": "password"
}
}
}
```
Pact Broker will respond with:
```json
{
"status": 404,
"headers": {
"Content-Type": "application/hal+json;charset=utf-8"
}
}
```
<a name="a_request_to_create_a_webhook_with_a_JSON_body_for_a_consumer_and_provider_given_the_&#39;Pricing_Service&#39;_and_&#39;Condor&#39;_already_exist_in_the_pact-broker"></a>
Given **the 'Pricing Service' and 'Condor' already exist in the pact-broker**, upon receiving **a request to create a webhook with a JSON body for a consumer and provider** from Pact Broker Client, with
```json
{
"method": "post",
"path": "/webhooks/provider/Pricing%20Service/consumer/Condor",
"headers": {
"Content-Type": "application/json",
"Accept": "application/hal+json"
},
"body": {
"events": [
{
"name": "contract_content_changed"
}
],
"request": {
"url": "https://webhook",
"method": "POST",
"headers": {
"Foo": "bar",
"Bar": "foo"
},
"body": {
"some": "body"
},
"username": "username",
"password": "password"
}
}
}
```
Pact Broker will respond with:
```json
{
"status": 201,
"headers": {
"Content-Type": "application/hal+json;charset=utf-8"
},
"body": {
"_links": {
"self": {
"href": "http://localhost:1234/some-url",
"title": "A title"
}
}
}
}
```
<a name="a_request_to_create_a_webhook_with_a_non-JSON_body_for_a_consumer_and_provider_given_the_&#39;Pricing_Service&#39;_and_&#39;Condor&#39;_already_exist_in_the_pact-broker"></a>
Given **the 'Pricing Service' and 'Condor' already exist in the pact-broker**, upon receiving **a request to create a webhook with a non-JSON body for a consumer and provider** from Pact Broker Client, with
```json
{
"method": "post",
"path": "/webhooks/provider/Pricing%20Service/consumer/Condor",
"headers": {
"Content-Type": "application/json",
"Accept": "application/hal+json"
},
"body": {
"events": [
{
"name": "contract_content_changed"
}
],
"request": {
"url": "https://webhook",
"method": "POST",
"headers": {
"Foo": "bar",
"Bar": "foo"
},
"body": "<xml></xml>",
"username": "username",
"password": "password"
}
}
}
```
Pact Broker will respond with:
```json
{
"status": 201,
"headers": {
"Content-Type": "application/hal+json;charset=utf-8"
},
"body": {
"_links": {
"self": {
"href": "http://localhost:1234/some-url",
"title": "A title"
}
}
}
}
```
<a name="a_request_to_get_the_Pricing_Service_given_the_&#39;Pricing_Service&#39;_already_exists_in_the_pact-broker"></a>
Given **the 'Pricing Service' already exists in the pact-broker**, upon receiving **a request to get the Pricing Service** from Pact Broker Client, with
```json
Expand Down Expand Up @@ -1247,3 +1392,51 @@ Pact Broker will respond with:
}
}
```
<a name="an_invalid_request_to_create_a_webhook_for_a_consumer_and_provider_given_the_&#39;Pricing_Service&#39;_and_&#39;Condor&#39;_already_exist_in_the_pact-broker"></a>
Given **the 'Pricing Service' and 'Condor' already exist in the pact-broker**, upon receiving **an invalid request to create a webhook for a consumer and provider** from Pact Broker Client, with
```json
{
"method": "post",
"path": "/webhooks/provider/Pricing%20Service/consumer/Condor",
"headers": {
"Content-Type": "application/json",
"Accept": "application/hal+json"
},
"body": {
"events": [
{
"name": "contract_content_changed"
}
],
"request": {
"url": null,
"method": "POST",
"headers": {
"Foo": "bar",
"Bar": "foo"
},
"body": {
"some": "body"
},
"username": "username",
"password": "password"
}
}
}
```
Pact Broker will respond with:
```json
{
"status": 400,
"headers": {
"Content-Type": "application/hal+json;charset=utf-8"
},
"body": {
"errors": {
"request.url": [
"Some error"
]
}
}
}
```
57 changes: 57 additions & 0 deletions lib/pact_broker/client/cli/broker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,63 @@ def describe_version
exit(1) unless result.success
end

method_option :request, aliases: "-X", desc: "HTTP method", required: true
method_option :header, aliases: "-H", type: :array, desc: "Header"
method_option :data, aliases: "-d", desc: "Data"
method_option :user, aliases: "-u", desc: "Basic auth username and password eg. username:password"
method_option :consumer, desc: "Consumer name", required: true
method_option :provider, desc: "Provider name", required: true
method_option :broker_base_url, required: true, aliases: "-b", desc: "The base URL of the Pact Broker"
method_option :broker_username, aliases: "-u", desc: "Pact Broker basic auth username"
method_option :broker_password, aliases: "-p", desc: "Pact Broker basic auth password"
method_option :contract_content_changed, type: :boolean, desc: "Trigger this webhook when the pact content changes"
method_option :provider_verification_published, type: :boolean, desc: "Trigger this webhook when a provider verification result is published"
method_option :verbose, aliases: "-v", type: :boolean, default: false, required: false, desc: "Verbose output. Default: false"

desc 'create-webhook URL', 'Creates a webhook using the same switches as a curl request.'
long_desc File.read(File.join(File.dirname(__FILE__), 'create_webhook_long_desc.txt'))
def create_webhook webhook_url
require 'pact_broker/client/webhooks/create'

if !(options.contract_content_changed || options.provider_verification_published)
raise PactBroker::Client::Error.new("You must select at least one of --contract-content-changed or --provider-verification-published")
end

username = options.user ? options.user.split(":", 2).first : nil
password = options.user ? options.user.split(":", 2).last : nil

headers = options.header.each_with_object({}) { | header, headers | headers[header.split(":", 2).first.strip] = header.split(":", 2).last.strip }

body = options.data
if body.start_with?("@")
filepath = body[1..-1]
begin
body = File.read(filepath)
rescue StandardError => e
raise PactBroker::Client::Error.new("Couldn't read data from file \"#{filepath}\" due to #{e.class} #{e.message}")
end
end

events = []
events << 'contract_content_changed' if options.contract_content_changed
events << 'provider_verification_published' if options.provider_verification_published

params = {
http_method: options.request,
url: webhook_url,
headers: headers,
username: username,
password: password,
body: body,
consumer: options.consumer,
provider: options.provider,
events: events
}
result = PactBroker::Client::Webhooks::Create.call(params, options.broker_base_url, pact_broker_client_options)
$stdout.puts result.message
exit(1) unless result.success
end

desc 'version', "Show the pact_broker-client gem version"
def version
$stdout.puts PactBroker::Client::VERSION
Expand Down
1 change: 1 addition & 0 deletions lib/pact_broker/client/cli/create_webhook_long_desc.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Create a curl command that executes the request that you want your webhook to execute, then replace "curl" with "pact-broker create-webhook" and add the consumer, provider, event types and broker details. Note that the URL must be the first parameter when executing create-webhook.
3 changes: 3 additions & 0 deletions lib/pact_broker/client/hal.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
require 'pact_broker/client/hal/link'
require 'pact_broker/client/hal/http_client'
require 'pact_broker/client/hal/entity'
53 changes: 53 additions & 0 deletions lib/pact_broker/client/webhooks/create.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
require 'uri'
require 'pact_broker/client/hal'
require 'ostruct'
require 'json'
require 'pact_broker/client/command_result'

module PactBroker
module Client
module Webhooks
class Create
attr_reader :params, :pact_broker_base_url, :basic_auth_options, :verbose

def self.call(params, pact_broker_base_url, pact_broker_client_options)
new(params, pact_broker_base_url, pact_broker_client_options).call
end

def initialize(params, pact_broker_base_url, pact_broker_client_options)
@params = OpenStruct.new(params)
@pact_broker_base_url = pact_broker_base_url
@basic_auth_options = pact_broker_client_options[:basic_auth] || {}
@verbose = pact_broker_client_options[:verbose]
end

def call
request_body = JSON.parse(params.body) rescue params.body

body = {
events: params.events.collect{ | event | { "name" => event }},
request: {
url: params.url,
method: params.http_method,
headers: params.headers,
body: request_body,
username: params.username,
password: params.password
}
}

#TODO look for relation
create_webhook_url = "#{pact_broker_base_url.chomp("/")}/webhooks/provider/{provider}/consumer/{consumer}"
http_client = PactBroker::Client::Hal::HttpClient.new(basic_auth_options.merge(verbose: verbose))
link = PactBroker::Client::Hal::Link.new({"href" => create_webhook_url}, http_client)
entity = link.expand(consumer: params.consumer, provider: params.provider).post(body)
if entity.success?
CommandResult.new(true, "Webhook #{entity._link('self').title_or_name.inspect} created")
else
CommandResult.new(false, "Error creating webhook. response status=#{entity.response.code} body=#{entity.response.body}")
end
end
end
end
end
end
Loading

0 comments on commit e1ec885

Please sign in to comment.