Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Features/html formatter #342

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/pronto.rb
Expand Up @@ -49,6 +49,7 @@
require 'pronto/formatter/bitbucket_pull_request_formatter'
require 'pronto/formatter/bitbucket_server_pull_request_formatter'
require 'pronto/formatter/checkstyle_formatter'
require 'pronto/formatter/html_formatter'
require 'pronto/formatter/null_formatter'
require 'pronto/formatter/formatter'

Expand Down
Binary file added lib/pronto/assets/logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
119 changes: 119 additions & 0 deletions lib/pronto/assets/output.html.erb
@@ -0,0 +1,119 @@
<!DOCTYPE html>
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="https://unpkg.com/spectre.css/dist/spectre.min.css">
<link rel="stylesheet" href="https://unpkg.com/spectre.css/dist/spectre-icons.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js"></script>

<title>Code Analysis Report</title>
<style>
.logo {
width: 40px;
height: 40px;
}

.navbar-section h3 {
margin: 0 !important;
}

.copy-btn, .card-header {
cursor: pointer;
}

.code code {
background: rgb(247, 248, 220) !important;
line-height: 0.5;
}

.accordion[open] .accordion-body {
max-height: max-content !important;
}

header {
margin-bottom: 20px;
}

body {
font-size: 0.75rem !important;
}
</style>
</head>

<body>
<header class="navbar bg-dark">
<section class="navbar-section">
<h3>Code Analysis Report</h3>
</section>
<section class="navbar-section">
<a href="https://github.com/dongnhzigexn/pronto" class="btn btn-link text-light">GitHub</a>
</section>
</header>
<div class="container">
<div class="panel bg-gray">
<div class="panel-header">
<div class="panel-title text-bold"><%= pluralize(files.values.flatten.count, 'offense', no_for_zero: true) %> detected:</div>
</div>
<div class="panel-body">
<ul>
<% files.each do |path, offenses| %>
<li>
<a href="#offense_<%= path %>"> <%= path %> </a>
<span class="chip"><%= pluralize(offenses.count, 'offense') %></span>
<span class="copy-btn tooltip tooltip-right" data-tooltip="Copy relative path"
data-clipboard-text="<%= path %>">
<i class=" icon icon-copy"></i>
</span>
</li>
<% end %>
</ul>
</div>
</div>

<% files.each do |path, offenses| %>
<details class="card mt-2 accordion" id="offense_<%= path %>">
<summary class="accordition-header card-header bg-gray text-bold">
<%= path %>
<span class="chip">
<%= pluralize(offenses.count, 'offense') %>
</span>
</summary>
<div class="card-body accordion-body">
<% offenses.each do |offense| %>
<div class="report">
<div class="meta text-italic">
<span class="copy-btn tooltip tooltip-right"
data-tooltip="Copy relative path"
data-clipboard-text="<%= path %>:<%= offense.line.new_lineno %>">
<a>Line #<%= offense.line.new_lineno %></a>
</span>
<%- message = "#{offense.level}: #{decorated_message(offense.msg)}" %>
<span class="message">
<%= message %>
</span>
<span class="chip">
<%= offense.runner.to_s.split('::').last %>
</span>
</div>
<pre class="code text-error"><code><%= offense.line.line.content.force_encoding('UTF-8') %></code></pre>
</div>
<% end %>
</div>
</details>
<% end %>
</div>
<script>
(function () {
var clipboard = new ClipboardJS('.copy-btn');
clipboard.on('success', function (e) {
buttons = document.getElementsByClassName('copy-btn');
for (let btn of buttons){
btn.dataset.tooltip = "Copy relative path"
}
e.trigger.dataset.tooltip = "Copied!"
});
})();
</script>
</body>
</html>
1 change: 1 addition & 0 deletions lib/pronto/formatter/formatter.rb
Expand Up @@ -22,6 +22,7 @@ def self.names
'json' => JsonFormatter,
'checkstyle' => CheckstyleFormatter,
'text' => TextFormatter,
'html' => HtmlFormatter,
'null' => NullFormatter
}.freeze
end
Expand Down
84 changes: 84 additions & 0 deletions lib/pronto/formatter/html_formatter.rb
@@ -0,0 +1,84 @@
# frozen_string_literal: true

require 'cgi'
require 'erb'
require 'ostruct'
require 'base64'

module Pronto
module Formatter
class HtmlFormatter < Base
TEMPLATE_PATH =
File.expand_path('../assets/output.html.erb', __dir__)

Color = Struct.new(:red, :green, :blue, :alpha) do
def to_s
"rgba(#{values.join(', ')})"
end

def fade_out(amount)
dup.tap do |color|
color.alpha -= amount
end
end
end

attr_reader :files, :summary

def format(messages, _, _)
render_html(messages)
end

def render_html(messages)
context = ERBContext.new(messages)

template = File.read(TEMPLATE_PATH, encoding: Encoding::UTF_8)

erb = if RUBY_VERSION >= '2.6'
ERB.new(template, trim_mode: '-')
else
ERB.new(template, nil, '-')
end
html = erb.result(context.binding)

html
end

# This class provides helper methods used in the ERB template.
class ERBContext

attr_reader :files

def initialize(messages)
@files = messages.group_by(&:path)
end

# Make Kernel#binding public.
def binding
super
end

def decorated_message(msg)
msg.gsub(/`(.+?)`/) do
"<code>#{Regexp.last_match(1)}</code>"
end.force_encoding('UTF-8')
end

def pluralize(number, thing, options = {})
if number.zero? && options[:no_for_zero]
"no #{thing}s"
elsif number == 1
"1 #{thing}"
else
"#{number} #{thing}s"
end
end

def escape(string)
CGI.escapeHTML(string)
end
end
end
end
end