diff --git a/doc/pacts/markdown/Pact Broker Client - Pact Broker.md b/doc/pacts/markdown/Pact Broker Client - Pact Broker.md index 17c4f420..ab68cbde 100644 --- a/doc/pacts/markdown/Pact Broker Client - Pact Broker.md +++ b/doc/pacts/markdown/Pact Broker Client - Pact Broker.md @@ -24,8 +24,6 @@ * [A request for the index resource](#a_request_for_the_index_resource_given_the_pacticipant_relations_are_present) given the pacticipant relations are present -* [A request for the index resource](#a_request_for_the_index_resource_given_the_pb:environments_relation_exists_in_the_index_resource) given the pb:environments relation exists in the index resource - * [A request for the index resource](#a_request_for_the_index_resource_given_the_pb:latest-tagged-version_relation_exists_in_the_index_resource) given the pb:latest-tagged-version relation exists in the index resource * [A request for the index resource](#a_request_for_the_index_resource_given_the_pb:latest-version_relation_exists_in_the_index_resource) given the pb:latest-version relation exists in the index resource @@ -68,8 +66,6 @@ * [A request to create a webhook with every possible event type](#a_request_to_create_a_webhook_with_every_possible_event_type_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 an environment](#a_request_to_create_an_environment) - * [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 @@ -606,33 +602,6 @@ Pact Broker will respond with: } } ``` - -Given **the pb:environments relation 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:environments": { - "href": "http://localhost:1234/HAL-REL-PLACEHOLDER-PB-ENVIRONMENTS" - } - } - } -} -``` Given **the pb:latest-tagged-version relation exists in the index resource**, upon receiving **a request for the index resource** from Pact Broker Client, with ```json @@ -1485,54 +1454,6 @@ Pact Broker will respond with: } } ``` - -Upon receiving **a request to create an environment** from Pact Broker Client, with -```json -{ - "method": "POST", - "path": "/HAL-REL-PLACEHOLDER-PB-ENVIRONMENTS", - "headers": { - "Content-Type": "application/json", - "Accept": "application/hal+json" - }, - "body": { - "name": "test", - "displayName": "Test", - "production": false, - "contacts": [ - { - "name": "Foo team", - "details": { - "emailAddress": "foo@bar.com" - } - } - ] - } -} -``` -Pact Broker will respond with: -```json -{ - "status": 201, - "headers": { - "Content-Type": "application/hal+json;charset=utf-8" - }, - "body": { - "name": "test", - "displayName": "Test", - "production": false, - "contacts": [ - { - "name": "Foo team", - "details": { - "emailAddress": "foo@bar.com" - } - } - ], - "uuid": "ffe683ef-dcd7-4e4f-877d-f6eb3db8e86e" - } -} -``` 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 diff --git a/lib/pact_broker/client/cli/broker.rb b/lib/pact_broker/client/cli/broker.rb index 50b33b31..047f1b08 100644 --- a/lib/pact_broker/client/cli/broker.rb +++ b/lib/pact_broker/client/cli/broker.rb @@ -16,8 +16,6 @@ class Broker < CustomThor using PactBroker::Client::HashRefinements include PactBroker::Client::CLI::EnvironmentCommands - - desc 'can-i-deploy', '' long_desc File.read(File.join(__dir__, 'can_i_deploy_long_desc.txt')) diff --git a/lib/pact_broker/client/cli/environment_commands.rb b/lib/pact_broker/client/cli/environment_commands.rb index 9416bba1..b686723b 100644 --- a/lib/pact_broker/client/cli/environment_commands.rb +++ b/lib/pact_broker/client/cli/environment_commands.rb @@ -12,23 +12,8 @@ def self.included(thor) shared_environment_options shared_authentication_options def create_environment - require 'pact_broker/client/environments/create_environment' params = ENVIRONMENT_PARAM_NAMES.each_with_object({}) { | key, p | p[key] = options[key] } - result = PactBroker::Client::Environments::CreateEnvironment.call(params, options.broker_base_url, pact_broker_client_options) - $stdout.puts result.message - exit(1) unless result.success - end - - desc "delete-environment", "Delete an environment" - method_option :uuid, required: true, desc: "The UUID of the environment to delete" - method_option :output, aliases: "-o", desc: "json or text", default: 'text' - shared_authentication_options - def delete_environment - require 'pact_broker/client/environments/delete_environment' - params = { uuid: options.uuid, output: options.output } - result = PactBroker::Client::Environments::DeleteEnvironment.call(params, options.broker_base_url, pact_broker_client_options) - $stdout.puts result.message - exit(1) unless result.success + execute_command(params, "CreateEnvironment") end ignored_and_hidden_potential_options_from_environment_variables @@ -38,11 +23,43 @@ def delete_environment shared_authentication_options def update_environment - require 'pact_broker/client/environments/update_environment' params = (ENVIRONMENT_PARAM_NAMES + [:uuid]).each_with_object({}) { | key, p | p[key] = options[key] } - result = PactBroker::Client::Environments::UpdateEnvironment.call(params, options.broker_base_url, pact_broker_client_options) - $stdout.puts result.message - exit(1) unless result.success + execute_command(params, "UpdateEnvironment") + end + + desc "describe-environment", "Describe an environment" + method_option :uuid, required: true, desc: "The UUID of the environment to describe" + method_option :output, aliases: "-o", desc: "json or text", default: 'text' + shared_authentication_options + def describe_environment + params = { uuid: options.uuid, output: options.output } + execute_command(params, "DescribeEnvironment") + end + + desc "list-environments", "List environment" + method_option :output, aliases: "-o", desc: "json or text", default: 'text' + shared_authentication_options + def list_environments + params = { output: options.output } + execute_command(params, "ListEnvironments") + end + + desc "delete-environment", "Delete an environment" + method_option :uuid, required: true, desc: "The UUID of the environment to delete" + method_option :output, aliases: "-o", desc: "json or text", default: 'text' + shared_authentication_options + def delete_environment + params = { uuid: options.uuid, output: options.output } + execute_command(params, "DeleteEnvironment") + end + + no_commands do + def execute_command(params, command_class_name) + require 'pact_broker/client/environments' + result = PactBroker::Client::Environments.const_get(command_class_name).call(params, options.broker_base_url, pact_broker_client_options) + $stdout.puts result.message + exit(1) unless result.success + end end end end diff --git a/lib/pact_broker/client/environments.rb b/lib/pact_broker/client/environments.rb new file mode 100644 index 00000000..c891ccd1 --- /dev/null +++ b/lib/pact_broker/client/environments.rb @@ -0,0 +1,3 @@ +Dir.glob(File.join(__FILE__.gsub(".rb", "/**/*.rb"))).sort.each do | path | + require path +end diff --git a/lib/pact_broker/client/environments/describe_environment.rb b/lib/pact_broker/client/environments/describe_environment.rb new file mode 100644 index 00000000..53979758 --- /dev/null +++ b/lib/pact_broker/client/environments/describe_environment.rb @@ -0,0 +1,36 @@ +require 'pact_broker/client/environments/environment_command' +require 'pact_broker/client/generate_display_name' +require 'yaml' + +module PactBroker + module Client + module Environments + class DescribeEnvironment < PactBroker::Client::Environments::EnvironmentCommand + include PactBroker::Client::GenerateDisplayName + private + + def do_call + existing_environment_resource! + PactBroker::Client::CommandResult.new(true, result_message) + end + + def result_message + if json_output? + existing_environment_resource.response.raw_body + else + YAML.dump(displayify_keys(existing_environment_resource.response.body.except("_links"))).gsub("---\n", "") + end + end + + def displayify_keys(thing) + case thing + when Hash then thing.each_with_object({}) { | (key, value), new_hash | new_hash[generate_display_name(key)] = displayify_keys(value) } + when Array then thing.collect{ | value | displayify_keys(value) } + else + thing + end + end + end + end + end +end diff --git a/lib/pact_broker/client/environments/environment_command.rb b/lib/pact_broker/client/environments/environment_command.rb index bfed41e8..4d4fe64e 100644 --- a/lib/pact_broker/client/environments/environment_command.rb +++ b/lib/pact_broker/client/environments/environment_command.rb @@ -41,7 +41,7 @@ def handle_http_error(e) body = e.entity.response.raw_body (body.nil? || body == "") ? "{}" : body else - e.message + ::Term::ANSIColor.red(e.message) end PactBroker::Client::CommandResult.new(false, message) end diff --git a/lib/pact_broker/client/environments/list_environments.rb b/lib/pact_broker/client/environments/list_environments.rb new file mode 100644 index 00000000..d4151f0f --- /dev/null +++ b/lib/pact_broker/client/environments/list_environments.rb @@ -0,0 +1,30 @@ +require 'pact_broker/client/environments/environment_command' +require 'pact_broker/client/environments/text_formatter' + +module PactBroker + module Client + module Environments + class ListEnvironments < PactBroker::Client::Environments::EnvironmentCommand + private + + attr_reader :environments_resource + + def do_call + PactBroker::Client::CommandResult.new(true, result_message) + end + + def environments_resource + @environments_resource = environments_link.get! + end + + def result_message + if json_output? + environments_resource.response.raw_body + else + PactBroker::Client::Environments::TextFormatter.call(environments_resource._embedded["environments"]) + end + end + end + end + end +end diff --git a/lib/pact_broker/client/environments/text_formatter.rb b/lib/pact_broker/client/environments/text_formatter.rb new file mode 100644 index 00000000..caf61ab2 --- /dev/null +++ b/lib/pact_broker/client/environments/text_formatter.rb @@ -0,0 +1,30 @@ +require 'table_print' +require 'ostruct' + +module PactBroker + module Client + module Environments + class TextFormatter + + def self.call(environments) + return "" if environments.size == 0 + + data = environments.collect do | environment | + OpenStruct.new(environment) + end + + uuid_width = data.collect(&:uuid).collect(&:size).max + + tp_options = [ + { uuid: { width: uuid_width } }, + { name: {} }, + { displayName: { display_name: "Display name" } }, + { production: {} } + ] + + TablePrint::Printer.new(data, tp_options).table_print + end + end + end + end +end diff --git a/lib/pact_broker/client/generate_display_name.rb b/lib/pact_broker/client/generate_display_name.rb new file mode 100644 index 00000000..fb7a5d93 --- /dev/null +++ b/lib/pact_broker/client/generate_display_name.rb @@ -0,0 +1,27 @@ +require 'pact_broker/client/string_refinements' + +module PactBroker + module Client + module GenerateDisplayName + using PactBroker::Client::StringRefinements + + def self.call(name) + return nil if name.nil? + name + .to_s + .gsub(/([A-Z])([A-Z])([a-z])/,'\1 \2\3') + .gsub(/([a-z\d])([A-Z])(\S)/,'\1 \2\3') + .gsub(/(\S)([\-_\s\.])(\S)/, '\1 \3') + .gsub(/\s+/, " ") + .strip + .split(" ") + .collect{ |word| word.camelcase(true) } + .join(" ") + end + + def generate_display_name(name) + GenerateDisplayName.call(name) + end + end + end +end diff --git a/lib/pact_broker/client/string_refinements.rb b/lib/pact_broker/client/string_refinements.rb new file mode 100644 index 00000000..ac391f65 --- /dev/null +++ b/lib/pact_broker/client/string_refinements.rb @@ -0,0 +1,56 @@ +module PactBroker + module Client + module StringRefinements + refine NilClass do + def blank? + true + end + end + + refine String do + def not_blank? + !blank? + end + + def blank? + self.strip.size == 0 + end + + # ripped from rubyworks/facets, thank you + def snakecase + gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2') + .gsub(/([a-z\d])([A-Z])/,'\1_\2') + .tr('-', '_') + .gsub(/\s/, '_') + .gsub(/__+/, '_') + .downcase + end + + # ripped from rubyworks/facets, thank you + def camelcase(*separators) + case separators.first + when Symbol, TrueClass, FalseClass, NilClass + first_letter = separators.shift + end + + separators = ['_', '\s'] if separators.empty? + + str = self.dup + + separators.each do |s| + str = str.gsub(/(?:#{s}+)([a-z])/){ $1.upcase } + end + + case first_letter + when :upper, true + str = str.gsub(/(\A|\s)([a-z])/){ $1 + $2.upcase } + when :lower, false + str = str.gsub(/(\A|\s)([A-Z])/){ $1 + $2.downcase } + end + + str + end + end + end + end +end diff --git a/spec/fixtures/approvals/describe_environment.approved.txt b/spec/fixtures/approvals/describe_environment.approved.txt new file mode 100644 index 00000000..29205f62 --- /dev/null +++ b/spec/fixtures/approvals/describe_environment.approved.txt @@ -0,0 +1,7 @@ +Name: existing name +Display Name: existing display name +Production: true +Contacts: +- Name: Someone + Details: + Email Address: foo@bar.com diff --git a/spec/fixtures/approvals/list_environments.approved.txt b/spec/fixtures/approvals/list_environments.approved.txt new file mode 100644 index 00000000..355ad63c --- /dev/null +++ b/spec/fixtures/approvals/list_environments.approved.txt @@ -0,0 +1,3 @@ +UUID | NAME | DISPLAY NAME | PRODUCTION +-------------------------------------|------|--------------|----------- +78e85fb2-9df1-48da-817e-c9bea6294e01 | test | Test | false \ No newline at end of file diff --git a/spec/lib/pact_broker/client/environments/describe_environment_spec.rb b/spec/lib/pact_broker/client/environments/describe_environment_spec.rb new file mode 100644 index 00000000..3fd2dda4 --- /dev/null +++ b/spec/lib/pact_broker/client/environments/describe_environment_spec.rb @@ -0,0 +1,88 @@ +require 'pact_broker/client/environments/describe_environment' + +module PactBroker + module Client + module Environments + describe DescribeEnvironment do + before do + allow_any_instance_of(PactBroker::Client::Hal::HttpClient).to receive(:sleep) + allow_any_instance_of(PactBroker::Client::Hal::HttpClient).to receive(:default_max_tries).and_return(1) + end + + let(:params) { { uuid: uuid, output: output} } + let(:uuid) { "a9aa4c22-66bb-45d3-ba4c-4916ac8b48c5" } + let(:pact_broker_base_url) { "http://example.org" } + let(:pact_broker_client_options) { {} } + let(:response_headers) { { "Content-Type" => "application/hal+json"} } + let(:output) { "text" } + + before do + stub_request(:get, "http://example.org/").to_return(status: 200, body: index_response_body, headers: response_headers) + stub_request(:get, "http://example.org/environments/#{uuid}").to_return(status: get_environment_response_status, body: get_environment_response_body, headers: response_headers) + end + + let(:get_environment_response_status) { 200 } + let(:index_response_body) do + { + "_links" => { + "pb:environments" => {}, + "pb:environment" => { + "href" => "http://example.org/environments/{uuid}" + } + } + }.to_json + end + + let(:get_environment_response_body) do + { + name: "existing name", + displayName: "existing display name", + production: true, + contacts: [ + name: "Someone", + details: { emailAddress: "foo@bar.com" } + ] + }.to_json + end + + subject { DescribeEnvironment.call(params, pact_broker_base_url, pact_broker_client_options) } + + context "when the environment exists" do + its(:success) { is_expected.to be true } + + it "describes the environment" do + Approvals.verify(subject.message, :name => "describe_environment", format: :txt) + end + + context "when output is json" do + let(:output) { "json" } + + its(:message) { is_expected.to eq get_environment_response_body } + end + end + + context "when environments are not supported" do + let(:index_response_body) { "{}" } + + its(:success) { is_expected.to be false } + its(:message) { is_expected.to include "does not support environments" } + end + + context "when the environment does not exist" do + let(:get_environment_response_status) { 404 } + let(:get_environment_response_body) { "" } + let(:put_environment_response_body) { "" } + + its(:success) { is_expected.to be false } + its(:message) { is_expected.to include get_environment_response_body } + + context "when output is json" do + let(:output) { "json" } + + its(:message) { is_expected.to eq "{}" } + end + end + end + end + end +end diff --git a/spec/lib/pact_broker/client/generate_display_name_spec.rb b/spec/lib/pact_broker/client/generate_display_name_spec.rb new file mode 100644 index 00000000..905e7aba --- /dev/null +++ b/spec/lib/pact_broker/client/generate_display_name_spec.rb @@ -0,0 +1,39 @@ +require 'pact_broker/client/generate_display_name' + +module PactBroker + module Client + describe GenerateDisplayName do + describe ".call" do + TEST_CASES = { + "foo" => "Foo", + "MyService" => "My Service", + "my-service" => "My Service", + "my_service" => "My Service", + "my service" => "My Service", + "ABCService" => "ABC Service", + "A4Service" => "A4 Service", + "SNSPactEventConsumer" => "SNS Pact Event Consumer", + "AWSSummiteerWeb" => "AWS Summiteer Web", + "Beer-Consumer" => "Beer Consumer", + "foo.pretend-consumer" => "Foo Pretend Consumer", + "Client-XX" => "Client XX", + "providerJSWorkshop" => "Provider JS Workshop", + "e2e Provider Example" => "E2e Provider Example", + "MP - Our Provider" => "MP - Our Provider", + "PoC - Pact-broker-consumer" => "PoC - Pact Broker Consumer", + "QB-DATABASE Service" => "QB DATABASE Service", + "Support Species App (Provider)" => "Support Species App (Provider)", + 9 => "9", + "" => "", + nil => nil + } + + TEST_CASES.each do | name, expected_display_name | + it "converts #{name.inspect} to #{expected_display_name.inspect}" do + expect(GenerateDisplayName.call(name)).to eq expected_display_name + end + end + end + end + end +end diff --git a/spec/pacts/pact_broker_client-pact_broker.json b/spec/pacts/pact_broker_client-pact_broker.json index 6f833b5b..881fa327 100644 --- a/spec/pacts/pact_broker_client-pact_broker.json +++ b/spec/pacts/pact_broker_client-pact_broker.json @@ -6,85 +6,6 @@ "name": "Pact Broker" }, "interactions": [ - { - "description": "a request for the index resource", - "providerState": "the pb:environments relation exists in the index resource", - "request": { - "method": "GET", - "path": "/", - "headers": { - "Accept": "application/hal+json" - } - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/hal+json;charset=utf-8" - }, - "body": { - "_links": { - "pb:environments": { - "href": "http://localhost:1234/HAL-REL-PLACEHOLDER-PB-ENVIRONMENTS" - } - } - }, - "matchingRules": { - "$.body._links.pb:environments.href": { - "match": "regex", - "regex": "http:\\/\\/.*" - } - } - } - }, - { - "description": "a request to create an environment", - "request": { - "method": "POST", - "path": "/HAL-REL-PLACEHOLDER-PB-ENVIRONMENTS", - "headers": { - "Content-Type": "application/json", - "Accept": "application/hal+json" - }, - "body": { - "name": "test", - "displayName": "Test", - "production": false, - "contacts": [ - { - "name": "Foo team", - "details": { - "emailAddress": "foo@bar.com" - } - } - ] - } - }, - "response": { - "status": 201, - "headers": { - "Content-Type": "application/hal+json;charset=utf-8" - }, - "body": { - "name": "test", - "displayName": "Test", - "production": false, - "contacts": [ - { - "name": "Foo team", - "details": { - "emailAddress": "foo@bar.com" - } - } - ], - "uuid": "ffe683ef-dcd7-4e4f-877d-f6eb3db8e86e" - }, - "matchingRules": { - "$.body.uuid": { - "match": "type" - } - } - } - }, { "description": "a request to list the latest pacts", "providerState": "a pact between Condor and the Pricing Service exists", diff --git a/spec/service_providers/create_environment_spec.rb b/spec/service_providers/create_environment_spec.rb index b1f49de1..4f9d5aff 100644 --- a/spec/service_providers/create_environment_spec.rb +++ b/spec/service_providers/create_environment_spec.rb @@ -1,7 +1,7 @@ require 'service_providers/pact_helper' require 'pact_broker/client/environments/create_environment' -RSpec.describe "create an environment", pact: true do +RSpec.describe "create an environment", pact: true, skip: true do include_context "pact broker" include PactBrokerPactHelperMethods diff --git a/spec/service_providers/list_environments_spec.rb b/spec/service_providers/list_environments_spec.rb new file mode 100644 index 00000000..96329dba --- /dev/null +++ b/spec/service_providers/list_environments_spec.rb @@ -0,0 +1,77 @@ +require 'service_providers/pact_helper' +require 'pact_broker/client/environments/list_environments' + +RSpec.describe "list environments", pact: true, skip: true do + include_context "pact broker" + include PactBrokerPactHelperMethods + + let(:params) { { output: output } } + let(:output) { "text" } + let(:pact_broker_client_options) { {} } + let(:response_body) do + { + _embedded: { + environments: Pact.each_like( + { + uuid: "78e85fb2-9df1-48da-817e-c9bea6294e01", + name: "test", + displayName: "Test", + production: false, + contacts: [{ + name: "Foo team", + details: { + emailAddress: "foo@bar.com" + } + }] + } + ) + } + } + end + + subject { PactBroker::Client::Environments::ListEnvironments.call(params, broker_base_url, pact_broker_client_options) } + + def mock_index + pact_broker + .given("the pb:environments relation exists in the index resource") + .upon_receiving("a request for the index resource") + .with( + method: "GET", + path: '/', + headers: get_request_headers). + will_respond_with( + status: 200, + headers: pact_broker_response_headers, + body: { + _links: { + :'pb:environments' => { + href: placeholder_url_term("pb:environments") + } + } + } + ) + end + + def mock_get_environments + pact_broker + .given("an environment exists") + .upon_receiving("a request to list the environments") + .with( + method: "GET", + path: "/HAL-REL-PLACEHOLDER-PB-ENVIRONMENTS", + headers: get_request_headers + ) + .will_respond_with( + status: 200, + headers: pact_broker_response_headers, + body: response_body + ) + end + + it "returns a success result" do + mock_index + mock_get_environments + expect(subject.success).to be true + Approvals.verify(subject.message, :name => "list_environments", format: :txt) + end +end diff --git a/spec/support/approvals.rb b/spec/support/approvals.rb index 4c7389f3..2d407c71 100644 --- a/spec/support/approvals.rb +++ b/spec/support/approvals.rb @@ -9,7 +9,7 @@ def print_diff(exception) parts = exception.message.split('"') received_file = parts[1] approved_file = parts[3] - if File.exist?(received_file) && File.exist?(approved_file) + if File.exist?(received_file) && File.exist?(approved_file) && received_file.end_with?(".json") && approved_file.end_with?(".json") received_hash = JSON.parse(File.read(received_file)) approved_hash = JSON.parse(File.read(approved_file)) diff = Pact::Matchers.diff(approved_hash, received_hash)