Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }

gem 'bundler', '~> 1.16'
gem 'haml'
gem 'kramdown'

group :development, :test do
gem 'rake', '~> 12.3'
Expand All @@ -14,10 +15,6 @@ group :development, :test do
gem 'rubocop'
end

group :development do
gem 'commonmarker'
end

group :test do
gem 'simplecov', require: false
end
12 changes: 4 additions & 8 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@ GEM
remote: https://rubygems.org/
specs:
ast (2.4.0)
commonmarker (0.17.9)
ruby-enum (~> 0.5)
concurrent-ruby (1.0.5)
diff-lcs (1.3)
docile (1.3.0)
haml (5.0.4)
temple (>= 0.8.0)
tilt
i18n (1.0.1)
concurrent-ruby (~> 1.0)
json (2.1.0)
kramdown (2.3.1)
rexml
parallel (1.12.1)
parser (2.5.1.0)
ast (~> 2.4.0)
powerpack (0.1.1)
rainbow (3.0.0)
rake (12.3.3)
rexml (3.2.4)
rspec (3.7.0)
rspec-core (~> 3.7.0)
rspec-expectations (~> 3.7.0)
Expand All @@ -41,8 +39,6 @@ GEM
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-enum (0.7.2)
i18n
ruby-progressbar (1.9.0)
simplecov (0.16.1)
docile (~> 1.1)
Expand All @@ -58,8 +54,8 @@ PLATFORMS

DEPENDENCIES
bundler (~> 1.16)
commonmarker
haml
kramdown
rake (~> 12.3)
rspec (~> 3.0)
rspec_junit_formatter
Expand Down
4 changes: 1 addition & 3 deletions bin/run-dev
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ require 'bundler/setup'
require 'pathname'
$LOAD_PATH.unshift(Pathname.new(__FILE__).dirname.dirname.join('lib').to_s)

require 'commonmarker'
require 'yaml'
require 'test_summary_buildkite_plugin'

Expand All @@ -20,8 +19,7 @@ module TestSummaryBuildkitePlugin
log(args, stdin: stdin)
if args.first == 'annotate'
context = args[2]
content = CommonMarker.render_html(stdin)
html = HamlRender.render('test_layout', content: content)
html = Utils.standalone_markdown(stdin)
FileUtils.mkdir_p('tmp')
out = Pathname.new('tmp').join(context + '.html')
out.open('w') { |file| file.write(html) }
Expand Down
6 changes: 4 additions & 2 deletions lib/test_summary_buildkite_plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
require 'json'

require 'test_summary_buildkite_plugin/agent'
require 'test_summary_buildkite_plugin/error_handler'
require 'test_summary_buildkite_plugin/failure'
require 'test_summary_buildkite_plugin/formatter'
require 'test_summary_buildkite_plugin/haml_render'
require 'test_summary_buildkite_plugin/input'
require 'test_summary_buildkite_plugin/runner'
require 'test_summary_buildkite_plugin/main'
require 'test_summary_buildkite_plugin/processor'
require 'test_summary_buildkite_plugin/tap'
require 'test_summary_buildkite_plugin/truncater'
require 'test_summary_buildkite_plugin/utils'
Expand All @@ -18,6 +20,6 @@ def self.run
plugins = JSON.parse(ENV.fetch('BUILDKITE_PLUGINS'), symbolize_names: true)
# plugins is an array of hashes, keyed by <github-url>#<version>
options = plugins.find { |k, _| k.to_s.include?('test-summary') }.values.first
Runner.new(options).run
Main.new(options).run
end
end
13 changes: 13 additions & 0 deletions lib/test_summary_buildkite_plugin/error_handler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

module TestSummaryBuildkitePlugin
module ErrorHandler
def handle_error(err, diagnostics = nil)
if fail_on_error
raise err
else
Utils.log_error(err, diagnostics)
end
end
end
end
44 changes: 22 additions & 22 deletions lib/test_summary_buildkite_plugin/formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,55 @@

module TestSummaryBuildkitePlugin
class Formatter
def self.create(**options)
def self.create(input:, output_path:, options:)
options[:type] ||= 'details'
type = options[:type].to_sym
raise "Unknown type: #{type}" unless TYPES.key?(type)
TYPES[type].new(options)
TYPES[type].new(input: input, output_path: output_path, options: options)
end

class Base
attr_reader :options
attr_reader :input, :output_path, :options

def initialize(options = {})
def initialize(input:, output_path:, options:)
@input = input
@output_path = output_path
@options = options || {}
end

def markdown(input)
def markdown(truncate)
return nil if input.failures.count.zero?
[heading(input), input_markdown(input), footer(input)].compact.join("\n\n")
[heading(truncate), input_markdown(truncate), footer].compact.join("\n\n")
end

protected

def input_markdown(input)
if show_first.negative? || show_first >= include_failures(input).count
failures_markdown(include_failures(input))
def input_markdown(truncate)
failures = include_failures(truncate)

if show_first.negative? || show_first >= failures.count
failures_markdown(failures, truncate)
elsif show_first.zero?
details('Show failures', failures_markdown(include_failures(input)))
details('Show failures', failures_markdown(failures, truncate))
else
failures_markdown(include_failures(input)[0...show_first]) +
details('Show additional failures', failures_markdown(include_failures(input)[show_first..-1]))
failures_markdown(failures[0...show_first], false) +
details('Show additional failures', failures_markdown(failures[show_first..-1], truncate))
end
end

def failures_markdown(failures)
render_template('failures', failures: failures)
def failures_markdown(failures, truncate)
render_template('failures', failures: failures, output_path: truncate ? output_path : nil)
end

def heading(input)
def heading(truncate)
count = input.failures.count
show_count = include_failures(input).count
show_count = include_failures(truncate).count
s = "##### #{input.label}: #{count} failure#{'s' unless count == 1}"
s += "\n\n_Including first #{show_count} failures_" if show_count < count
s
end

def footer(input)
def footer
job_ids = input.failures.map(&:job_id).uniq.reject(&:nil?)
render_template('footer', job_ids: job_ids)
end
Expand All @@ -65,11 +69,7 @@ def type
options[:type] || 'details'
end

def truncate
options[:truncate]
end

def include_failures(input)
def include_failures(truncate)
if truncate
input.failures[0...truncate]
else
Expand Down
10 changes: 2 additions & 8 deletions lib/test_summary_buildkite_plugin/input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ def self.create(type:, **options)
end

class Base
include ErrorHandler

attr_reader :label, :artifact_path, :options

def initialize(label:, artifact_path:, **options)
Expand Down Expand Up @@ -77,14 +79,6 @@ def job_id_regex
DEFAULT_JOB_ID_REGEX
end
end

def handle_error(err)
if fail_on_error
raise err
else
Utils.log_error(err)
end
end
end

class OneLine < Base
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# frozen_string_literal: true

module TestSummaryBuildkitePlugin
class Runner
class Main
MAX_MARKDOWN_SIZE = 100_000
OUTPUT_PATH = 'test-summary.html'

attr_reader :options

Expand All @@ -11,23 +12,37 @@ def initialize(options)
end

def run
markdown = Truncater.new(
processor = Processor.new(
formatter_options: formatter,
max_size: MAX_MARKDOWN_SIZE,
output_path: OUTPUT_PATH,
inputs: inputs,
formatter_opts: options[:formatter],
fail_on_error: fail_on_error
).markdown
if markdown.nil? || markdown.empty?
)

if processor.truncated_markdown.nil? || processor.truncated_markdown.empty?
puts('No errors found! 🎉')
else
annotate(markdown)
upload_artifact(processor.inputs_markdown)
annotate(processor.truncated_markdown)
end
end

private

def upload_artifact(markdown)
File.write(OUTPUT_PATH, Utils.standalone_markdown(markdown))
Agent.run('artifact', 'upload', OUTPUT_PATH)
end

def annotate(markdown)
Agent.run('annotate', '--context', context, '--style', style, stdin: markdown)
end

def formatter
options[:formatter] || {}
end

def inputs
@inputs ||= options[:inputs].map { |opts| Input.create(opts.merge(fail_on_error: fail_on_error)) }
end
Expand Down
63 changes: 63 additions & 0 deletions lib/test_summary_buildkite_plugin/processor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# frozen_string_literal: true

module TestSummaryBuildkitePlugin
class Processor
include ErrorHandler

attr_reader :formatter_options, :max_size, :output_path, :inputs, :fail_on_error

def initialize(formatter_options:, max_size:, output_path:, inputs:, fail_on_error:)
@formatter_options = formatter_options
@max_size = max_size
@output_path = output_path
@inputs = inputs
@fail_on_error = fail_on_error
@_formatters = {}
end

def truncated_markdown
@truncated_markdown ||= begin
truncater = Truncater.new(
max_size: max_size,
max_truncate: inputs.map(&:failures).map(&:count).max
) do |truncate|
inputs_markdown(truncate)
end

truncater.markdown
rescue StandardError => e
handle_error(e, diagnostics)
HamlRender.render('truncater_exception', {})
end
end

def inputs_markdown(truncate = nil)
inputs.map { |input| input_markdown(input, truncate) }.compact.join("\n\n")
end

private

def input_markdown(input, truncate)
formatter(input).markdown(truncate)
rescue StandardError => e
handle_error(e)
end

def formatter(input)
@_formatters[input] ||= Formatter.create(input: input, output_path: output_path, options: formatter_options)
end

def diagnostics
{
formatter: formatter_options,
inputs: inputs.map do |input|
{
type: input.class,
failure_count: input.failures.count,
markdown_bytesize: input_markdown(input, nil)&.bytesize
}
end
}
end
end
end
Loading