module PactBroker module Client module CLI # Thor::Error will have its backtrace hidden class WebhookCreationError < ::Thor::Error; end module WebhookCommands def self.included(thor) thor.class_eval do no_commands do def self.shared_options_for_webhook_commands method_option :request, banner: "METHOD", aliases: "-X", desc: "Webhook HTTP method", required: true method_option :header, aliases: "-H", type: :array, desc: "Webhook Header" method_option :data, aliases: "-d", desc: "Webhook payload. Provide a JSON string (remember to escape characters appropriately for the shell) or a file path prefixed with the @ symbol, as per the curl usage for this flag." method_option :user, aliases: "-u", desc: "Webhook basic auth username and password eg. username:password" method_option :consumer, desc: "Consumer name" method_option :consumer_label, desc: "Consumer label, mutually exclusive with consumer name" method_option :provider, desc: "Provider name" method_option :provider_label, desc: "Provider label, mutually exclusive with provider name" method_option :description, desc: "Webhook description" method_option :contract_content_changed, type: :boolean, desc: "Trigger this webhook when the pact content changes" method_option :contract_published, type: :boolean, desc: "Trigger this webhook when a pact is published" method_option :provider_verification_published, type: :boolean, desc: "Trigger this webhook when a provider verification result is published" method_option :provider_verification_failed, type: :boolean, desc: "Trigger this webhook when a failed provider verification result is published" method_option :provider_verification_succeeded, type: :boolean, desc: "Trigger this webhook when a successful provider verification result is published" method_option :contract_requiring_verification_published, type: :boolean, desc: "Trigger this webhook when a contract is published that requires verification" method_option :team_uuid, banner: "UUID", desc: "UUID of the PactFlow team to which the webhook should be assigned (PactFlow only)" shared_authentication_options end end shared_options_for_webhook_commands 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 run_webhook_commands webhook_url end desc 'create-or-update-webhook URL', 'Creates or updates a webhook with a provided uuid and using the same switches as a curl request.' shared_options_for_webhook_commands method_option :uuid, type: :string, required: true, desc: "Specify the uuid for the webhook" long_desc File.read(File.join(File.dirname(__FILE__), 'create_or_update_webhook_long_desc.txt')) def create_or_update_webhook webhook_url run_webhook_commands webhook_url end desc 'test-webhook', 'Test the execution of a webhook' method_option :uuid, type: :string, required: true, desc: "Specify the uuid for the webhook" shared_authentication_options def test_webhook require 'pact_broker/client/webhooks/test' result = PactBroker::Client::Webhooks::Test.call(options, pact_broker_client_options) $stdout.puts result.message end no_commands do def parse_webhook_events events = [] events << 'contract_content_changed' if options.contract_content_changed events << 'contract_published' if options.contract_published events << 'provider_verification_published' if options.provider_verification_published events << 'provider_verification_succeeded' if options.provider_verification_succeeded events << 'provider_verification_failed' if options.provider_verification_failed events << 'contract_requiring_verification_published' if options.contract_requiring_verification_published events end def parse_webhook_options(webhook_url) validate_mutual_exclusiveness_of_participant_name_and_label_options events = parse_webhook_events # TODO update for contract_requiring_verification_published when released if events.size == 0 raise WebhookCreationError.new("You must specify at least one of --contract-content-changed, --contract-published, --provider-verification-published, --provider-verification-succeeded or --provider-verification-failed") 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 && body.start_with?("@") filepath = body[1..-1] begin body = File.read(filepath) rescue StandardError => e raise WebhookCreationError.new("Couldn't read data from file \"#{filepath}\" due to #{e.class} #{e.message}") end end { uuid: options.uuid, description: options.description, http_method: options.request, url: webhook_url, headers: headers, username: username, password: password, body: body, consumer: options.consumer, consumer_label: options.consumer_label, provider: options.provider, provider_label: options.provider_label, events: events, team_uuid: options.team_uuid } end def run_webhook_commands webhook_url require 'pact_broker/client/webhooks/create' validate_credentials result = PactBroker::Client::Webhooks::Create.call(parse_webhook_options(webhook_url), options.broker_base_url, pact_broker_client_options) $stdout.puts result.message exit(1) unless result.success rescue PactBroker::Client::Error => e raise WebhookCreationError, "#{e.class} - #{e.message}" end def validate_mutual_exclusiveness_of_participant_name_and_label_options if options.consumer && options.consumer_label raise WebhookCreationError.new("Consumer name (--consumer) and label (--consumer_label) options are mutually exclusive") end if options.provider && options.provider_label raise WebhookCreationError.new("Provider name (--provider) and label (--provider_label) options are mutually exclusive") end end end end end end end end end