Skip to content
Permalink
Browse files

Add HTML template for debug report

  • Loading branch information...
rrrene committed Jun 9, 2018
1 parent e38af78 commit 1776925c8c7ea7a5bdb6fd5ab12159adfc7cea53
@@ -11,3 +11,4 @@ erl_crash.dump
*.ez
lib/my_first_credo_check.ex
.tool-versions-e
credo-debug-log.html
@@ -0,0 +1,60 @@
<html>

<head>

<title>Credo Debug Log</title>

<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.css">

<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.js"></script>

</head>

<body>

<h1>Credo Debug Log</h1>

<h2>Check Timings</h2>

<table id="timing-data">
<thead>
<th>Started at</th>
<th>Tags</th>
<th>Duration (ms)</th>
</thead>
<tbody>
<%= for {tags, started_at, time} <- @timings do %>
<tr>
<td>
<%= started_at %>
</td>
<td>
<code>
<%= inspect(tags, pretty: true) %>
</code>
</td>
<td>
<%= div(time, 1000) %>
</td>
</tr>
<% end %>
</tbody>
</table>

<script>
$(document).ready(function () {
$('#timing-data').DataTable({});
});
</script>

<!--
<h2>Token</h2>
<pre><%= inspect(@exec, pretty: true) %></pre>
-->

</body>

</html>
@@ -7,87 +7,99 @@ defmodule Credo.Check.Runner do
alias Credo.CLI.Output.UI
alias Credo.Execution
alias Credo.Execution.Issues
alias Credo.Execution.Timing
alias Credo.SourceFile

@doc false
@doc """
Runs all checks on all source files (according to the config).
"""
def run(source_files, exec) when is_list(source_files) do
{_time_run_on_all, _source_files_after_run_on_all} =
:timer.tc(fn ->
run_checks_that_run_on_all(source_files, exec)
end)
checks = Execution.checks(exec)
{run_on_all_checks, other_checks} = Enum.split_with(checks, &run_on_all_check?/1)

{_time_run, _source_files} =
:timer.tc(fn ->
source_files
|> Enum.map(&Task.async(fn -> run(&1, exec) end))
|> Enum.map(&Task.await(&1, :infinity))
end)
run_on_all_checks
|> Enum.map(&Task.async(fn -> run_check_on_source_files(&1, source_files, exec) end))
|> Enum.each(&Task.await(&1, :infinity))

source_files
|> Enum.map(&Task.async(fn -> run_checks_and_append_issues(&1, exec, other_checks) end))
|> Enum.each(&Task.await(&1, :infinity))

:ok
end

def run(%SourceFile{} = source_file, exec) do
checks =
exec
|> Execution.checks()
|> Enum.reject(&run_on_all_check?/1)
defp run_on_all_check?({check}), do: check.run_on_all?
defp run_on_all_check?({check, _params}), do: check.run_on_all?

case run_checks(source_file, checks, exec) do
defp run_checks_and_append_issues(%SourceFile{} = source_file, exec, checks) do
case run_checks_individually(source_file, checks, exec) do
[] ->
nil

issues ->
Issues.append(exec, source_file, issues)
list ->
Enum.each(list, &append_issues_and_timings(exec, source_file, &1))
end

:ok
end

@doc "Runs the ConfigCommentFinder."
def run_config_comment_finder(source_files, exec) do
{Credo.Check.ConfigCommentFinder}
|> run_check(source_files, exec)
|> Enum.into(%{})
defp append_issues_and_timings(exec, source_file, {issues, nil}) do
Issues.append(exec, source_file, issues)
end

defp run_checks_that_run_on_all(source_files, exec) do
checks =
exec
|> Execution.checks()
|> Enum.filter(&run_on_all_check?/1)
defp append_issues_and_timings(exec, source_file, {issues, {check, filename, started_at, time}}) do
Issues.append(exec, source_file, issues)

checks
|> Enum.map(
&Task.async(fn ->
run_check(&1, source_files, exec)
end)
)
|> Enum.each(&Task.await(&1, :infinity))
Timing.append(exec, [check: check, source_file: filename], started_at, time)
end

:ok
defp append_issues_and_timings(exec, source_file, {issues, {check, started_at, time}}) do
Issues.append(exec, source_file, issues)

Timing.append(exec, [check: check], started_at, time)
end

defp run_checks(%SourceFile{} = source_file, checks, exec)
when is_list(checks) do
Enum.flat_map(checks, &run_check(&1, source_file, exec))
@doc false
def run_config_comment_finder(source_files, exec) do
case run_check_on_source_files({Credo.Check.ConfigCommentFinder}, source_files, exec) do
{issues, nil} ->
Enum.into(issues, %{})

{issues, {check, started_at, time}} ->
Timing.append(exec, [check: check, alias: "ConfigCommentFinder"], started_at, time)

Enum.into(issues, %{})
end
end

# Returns issues
defp run_check({_check, false}, source_files, _exec)
when is_list(source_files) do
source_files
#
# Run a single check on a list of source files
#

defp run_check_on_source_files({_check, false}, _source_files, _exec), do: []

defp run_check_on_source_files({check}, source_files, exec) do
run_check_on_source_files({check, []}, source_files, exec)
end

defp run_check({_check, false}, _source_file, _exec) do
[]
defp run_check_on_source_files(
{check, params},
source_files,
%Credo.Execution{debug: true} = exec
) do
{started_at, time, issues} =
Timing.run(fn ->
do_run_check_on_source_files({check, params}, source_files, exec)
end)

{issues, {check, started_at, time}}
end

defp run_check({check}, source_file, exec) do
run_check({check, []}, source_file, exec)
defp run_check_on_source_files({check, params}, source_files, exec) do
do_run_check_on_source_files({check, params}, source_files, exec)
end

defp run_check({check, params}, source_files, exec)
when is_list(source_files) do
defp do_run_check_on_source_files({check, params}, source_files, exec) do
try do
check.run(source_files, exec, params)
rescue
@@ -102,7 +114,42 @@ defmodule Credo.Check.Runner do
end
end

defp run_check({check, params}, source_file, exec) do
#
# Run a single check on a single source file
#

defp run_checks_individually(%SourceFile{} = source_file, checks, exec) do
Enum.map(checks, &run_check_on_single_source_file(&1, source_file, exec))
end

defp run_check_on_single_source_file({check}, source_file, exec) do
run_check_on_single_source_file({check, []}, source_file, exec)
end

defp run_check_on_single_source_file({_check, false}, _source_file, _exec), do: []

defp run_check_on_single_source_file(
{check, params},
source_file,
%Credo.Execution{debug: true} = exec
) do
started_at = Timing.now()

{started_at, time, issues} =
Timing.run(fn ->
do_run_check_on_single_source_file({check, params}, source_file, exec)
end)

{issues, {check, source_file.filename, started_at, time}}
end

defp run_check_on_single_source_file({check, params}, source_file, exec) do
issues = do_run_check_on_single_source_file({check, params}, source_file, exec)

{issues, nil}
end

defp do_run_check_on_single_source_file({check, params}, source_file, exec) do
try do
check.run(source_file, params)
rescue
@@ -124,7 +171,4 @@ defmodule Credo.Check.Runner do
defp warn_about_failed_run(check, _) do
UI.warn("Error while running #{check}")
end

defp run_on_all_check?({check}), do: check.run_on_all?
defp run_on_all_check?({check, _params}), do: check.run_on_all?
end
@@ -8,6 +8,7 @@ defmodule Credo.CLI do
"""

alias Credo.Execution
alias Credo.Execution.Task.WriteDebugReport
alias Credo.MainProcess
alias Credo.Service.Commands

@@ -19,6 +20,7 @@ defmodule Credo.CLI do

%Execution{argv: argv}
|> MainProcess.call()
|> WriteDebugReport.call([])
|> halt_if_exit_status_assigned()
end

@@ -4,11 +4,6 @@ defmodule Credo.Execution do
manipulated via the `Credo.Execution` module.
"""

@type t :: module

alias Credo.Execution.Issues
alias Credo.Execution.SourceFiles

defstruct argv: [],
cli_options: nil,

@@ -39,11 +34,18 @@ defmodule Credo.Execution do
halted: false,
source_files_pid: nil,
issues_pid: nil,
timing_pid: nil,
skipped_checks: nil,
assigns: %{},
results: %{},
config_comment_map: %{}

@type t :: module

alias Credo.Execution.Issues
alias Credo.Execution.SourceFiles
alias Credo.Execution.Timing

@doc """
Returns the checks that should be run for a given `exec` struct.
@@ -176,5 +178,6 @@ defmodule Credo.Execution do
exec
|> SourceFiles.start_server()
|> Issues.start_server()
|> Timing.start_server()
end
end
@@ -1,27 +1,34 @@
defmodule Credo.Execution.Monitor do
require Logger

import Credo.Execution

alias Credo.Execution.Timing

def task(exec, task, opts, fun, args) do
context_tuple = {:task, exec, task, opts}
log(:call_start, context_tuple)

{time, exec} = :timer.tc(fun, args)
{started_at, time, exec} = Timing.run(fun, args)

log(:call_end, context_tuple, time)

put_assign(exec, "credo.debug.time.tasks.#{task}", time)
Timing.append(exec, [task: task], started_at, time)

exec
end

def task_group(exec, task_group, opts, fun, args) do
context_tuple = {:task_group, exec, task_group, opts}
log(:call_start, context_tuple)

{time, exec} = :timer.tc(fun, args)
{started_at, time, exec} = Timing.run(fun, args)

log(:call_end, context_tuple, time)

put_assign(exec, "credo.debug.time.task_groups.#{task_group.name}", time)
Timing.append(exec, [task_group: task_group], started_at, time)

exec
end

defp log(:call_start, {:task_group, _exec, task_group, _opts}) do
@@ -0,0 +1,29 @@
defmodule Credo.Execution.Task.WriteDebugReport do
use Credo.Execution.Task

alias Credo.Execution.Timing
alias Credo.CLI.Output.UI

@debug_template_filename "debug-template.html"
@debug_output_filename "credo-debug-log.html"

def call(%Credo.Execution{debug: true} = exec, _opts) do
Logger.flush()

assigns = [exec: exec, timings: Timing.by_tag(exec, :check)]

content = EEx.eval_file(@debug_template_filename, assigns: assigns)

File.write!(@debug_output_filename, content)

IO.puts(content)

UI.puts([:green, "Debug log written to ", :reset, @debug_output_filename])

exec
end

def call(exec, _opts) do
exec
end
end
Oops, something went wrong.

0 comments on commit 1776925

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.