require 'pact_broker/client/error' require 'pact_broker/client/pact_broker_client' require 'pact_broker/client/retry' require 'pact_broker/client/matrix/formatter' require 'term/ansicolor' require 'pact_broker/client/colorize_notices' require "pact_broker/client/matrix/query" module PactBroker module Client class CanIDeploy class Result attr_reader :success, :message def initialize success, message = nil @success = success @message = message end end def self.call(version_selectors, matrix_options, options, pact_broker_client_options={}) new(version_selectors, matrix_options, options, pact_broker_client_options).call end def initialize(version_selectors, matrix_options, options, pact_broker_client_options) @version_selectors = version_selectors @matrix_options = matrix_options @options = options @pact_broker_client_options = pact_broker_client_options end def call create_result(fetch_matrix_with_retries) rescue StandardError => e Result.new(dry_run_or_false, for_dry_run(Term::ANSIColor.red("Error retrieving matrix. #{e.class} - #{e.message}") + "\n#{e.backtrace.join("\n")}")) end private attr_reader :version_selectors, :matrix_options, :options, :pact_broker_client_options def create_result(matrix) if matrix.deployable? Result.new(true, success_message(matrix)) else Result.new(dry_run_or_false, failure_message(matrix)) end end def success_message(matrix) message = format_matrix(matrix) if format != 'json' message = warning(matrix) + computer_says(true) + message + "\n\n" + notice_or_reason(matrix, :green) message = for_dry_run(message) end message end def failure_message(matrix) message = format_matrix(matrix) if format != 'json' message = warning(matrix) + computer_says(false) + message + "\n\n" + notice_or_reason(matrix, :red) message = for_dry_run(message) end message end def computer_says(success) if success if dry_run? "Computer says yes \\o/ (and maybe you don't need to enable dry run)" else Term::ANSIColor.green('Computer says yes \o/ ') end else if dry_run? "Computer says no ¯\\_(ツ)_/¯ (but you're ignoring this by enabling dry run)" else Term::ANSIColor.red("Computer says no ¯\\_(ツ)_/¯") end end end def notice_or_reason(matrix, reason_color) if matrix.notices PactBroker::Client::ColorizeNotices.call(matrix.notices).join("\n") else Term::ANSIColor.send(reason_color, matrix.reason) end end def format_matrix(matrix) formatted_matrix = Matrix::Formatter.call(matrix, format) if format != 'json' && formatted_matrix.size > 0 "\n\n" + formatted_matrix else formatted_matrix end end def format options[:output] end def fetch_matrix Retry.while_error { PactBroker::Client::Matrix::Query.call({ selectors: version_selectors, matrix_options: matrix_options }, options, pact_broker_client_options) } end def fetch_matrix_with_retries matrix = fetch_matrix if retry_while_unknown? && !dry_run_or_false check_if_retry_while_unknown_supported(matrix) if matrix.any_unknown? results = matrix.unknown_count == 1 ? "result" : "results" $stderr.puts "Waiting for #{matrix.unknown_count} verification #{results} to be published (maximum of #{wait_time} seconds)" matrix = Retry.until_truthy_or_max_times(retry_options) do fetch_matrix end end end matrix end def retry_while_unknown? options[:retry_while_unknown] > 0 end def dry_run? options[:dry_run] end def dry_run_or_false dry_run? || false end def for_dry_run(lines) if dry_run? prefix = Term::ANSIColor.yellow("[dry-run] ") lines.split("\n").collect { |line| prefix + Term::ANSIColor.uncolor(line) }.join("\n") + "\n" + prefix + "\n" + prefix + Term::ANSIColor.green("Dry run enabled - ignoring any failures") else lines end end def retry_options { condition: lambda { |matrix| !matrix.any_unknown? }, times: retry_tries, sleep: retry_interval, sleep_first: true } end def retry_interval options[:retry_interval] end def retry_tries options[:retry_while_unknown] end def wait_time retry_interval * retry_tries end def check_if_retry_while_unknown_supported(matrix) if !matrix.supports_unknown_count? raise PactBroker::Client::Error.new("This version of the Pact Broker does not provide a count of the unknown verification results. Please upgrade your Broker to >= v2.23.4") end end def warning(matrix) if matrix_options[:ignore_selectors] && matrix_options[:ignore_selectors].any? && !matrix.supports_ignore? Term::ANSIColor.yellow("WARN: This version of the Pact Broker does not support ignoring pacticipants. Please upgrade your Broker to >= 2.80.0") + "\n\n" else "" end end end end end