require 'pact/consumer_contract' require 'pact/reification' require 'redcarpet' require 'pact/doc/markdown/consumer_contract_renderer' require 'pact_broker/api/pact_broker_urls' require 'pact_broker/logging' module PactBroker module Api module Renderers class HtmlPactRenderer class NotAPactError < StandardError; end include PactBroker::Logging def self.call pact, options = {} new(pact, options).call end def initialize pact, options = {} @json_content = pact.json_content @pact = pact @options = options end def call "<html> <head>#{head}</head> <body> #{pact_metadata}#{html} </body> </html>" end private def head "<title>#{title}</title> <link rel='stylesheet' type='text/css' href='/stylesheets/github.css'> <link rel='stylesheet' type='text/css' href='/stylesheets/pact.css'> <link rel='stylesheet' type='text/css' href='/stylesheets/github-json.css'> <script src='/javascripts/highlight.pack.js'></script> <script src='/javascripts/jquery-2.1.1.min.js'></script> <script src='/js/bootstrap.min.js'></script> <script src='/javascripts/pact.js'></script> <script>hljs.initHighlightingOnLoad();</script>" end def pact_metadata "<div class='pact-metadata'> <ul> #{badge_list_item} #{badge_markdown_item} <li> <span class='name'>#{@pact.consumer.name} version:</span> <span class='value'>#{@pact.consumer_version_number}#{tags}</span> </li> <li> <span class='name'>Date published:</span> <span class='value'>#{published_date}</span> </li> <li> <a href=\"#{json_url}\">View in API Browser</a> </li> <li> <a href=\"/\">Home</a> </li> </ul> </div>" end def badge_list_item "<li class='badge'> <img src='#{badge_url}'/> </li> " end def badge_markdown_item "<li class='badge-markdown' style='display:none'> <textarea rows='3' cols='100'>#{badge_markdown}</textarea> </li>" end def badge_markdown warning = if badges_protected? "If the broker is protected by authentication, set `enable_public_badge_access` to true in the configuration to enable badges to be embedded in a markdown file.\n" else "" end "#{warning}[](#{badge_target_url})" end def badges_protected? !PactBroker.configuration.enable_public_badge_access end def base_url @options[:base_url] || '' end def title "Pact between #{@pact.consumer.name} and #{@pact.provider.name}" end def published_date @pact.created_at.to_time.localtime.to_datetime.strftime("%a %d %b %Y, %l:%M%P %:z") end def json_url PactBroker::Api::PactBrokerUrls.hal_browser_url pact_url end def pact_url PactBroker::Api::PactBrokerUrls.pact_url '', @pact end def badge_target_url base_url end def badge_url @options[:badge_url] end def tags if @pact.consumer_version_tag_names.any? " (#{@pact.consumer_version_tag_names.join(", ")})" else "" end end def markdown Pact::Doc::Markdown::ConsumerContractRenderer.call consumer_contract rescue NotAPactError heading = "### A contract between #{@pact.consumer.name} and #{@pact.provider.name}" warning = "_Note: this contract could not be parsed to a Pact, showing raw content instead._" pretty_json = JSON.pretty_generate(@pact.content_hash) "#{heading}\n#{warning}\n```json\n#{pretty_json}\n```\n" end def html Redcarpet::Markdown.new(Redcarpet::Render::HTML, :fenced_code_blocks => true, :lax_spacing => true).render(markdown) end def consumer_contract Pact::ConsumerContract.from_json(@json_content) rescue => e logger.warn "#{e.class} #{e.message} #{e.backtrace.join("\n")}" logger.warn "Could not parse the following content to a Pact, showing raw content instead: #{@json_content}" raise NotAPactError end end end end end