forked from Baguette/tap-aggregator
174 lines
3.9 KiB
Crystal
174 lines
3.9 KiB
Crystal
require "tap"
|
|
require "option_parser"
|
|
require "colorize"
|
|
|
|
class Storage
|
|
def initialize(@root : String = "storage")
|
|
end
|
|
|
|
def store(project, environment, revision, content)
|
|
date = Time.utc.to_unix
|
|
file_path = "#{@root}/#{project}/#{environment}/#{date}##{revision}.tap"
|
|
Dir.mkdir_p File.dirname file_path
|
|
File.write file_path, content
|
|
end
|
|
|
|
def projects
|
|
Dir.children @root
|
|
end
|
|
|
|
def environments(project)
|
|
Dir.children "#{@root}/#{project}"
|
|
end
|
|
|
|
def results(project, environment)
|
|
dir_name = "#{@root}/#{project}/#{environment}"
|
|
Dir.children(dir_name).compact_map do |file_name|
|
|
unless file_name.match /.tap$/
|
|
next
|
|
end
|
|
|
|
tap = Tap.parse File.read "#{dir_name}/#{file_name}"
|
|
next unless tap
|
|
|
|
md = file_name.match /^([^#]*)#(.*).tap$/
|
|
unless md
|
|
next
|
|
end
|
|
|
|
revision = md[2]
|
|
timestamp = md[1]
|
|
|
|
{revision, timestamp, tap}
|
|
end
|
|
end
|
|
end
|
|
|
|
Colorize.on_tty_only!
|
|
|
|
args = Array(String).new
|
|
show_projects = [] of String
|
|
show_environments = [] of String
|
|
show_revisions = [] of String
|
|
show_as_summary = true
|
|
|
|
OptionParser.parse! do |parser|
|
|
parser.banner = "usage: tap-aggregator <command> [options]"
|
|
|
|
parser.on("-h", "--help", "Show this help") do
|
|
puts parser
|
|
exit 0
|
|
end
|
|
|
|
parser.on("-p id", "--project id", "Filter results that do not match this project.") do |id|
|
|
show_projects << id
|
|
end
|
|
|
|
parser.on("-e id", "--environment id", "Filter results that do not match this environment.") do |id|
|
|
show_environments << id
|
|
end
|
|
|
|
parser.on("-r id", "--revision id", "Filter results that do not match this revision id.") do |id|
|
|
show_revisions << id
|
|
end
|
|
|
|
parser.on("-v", "--verbose", "Prints all data instead of just summaries.") do
|
|
show_as_summary = false
|
|
end
|
|
|
|
parser.invalid_option do |flag|
|
|
STDERR.puts "ERROR: #{flag} is not a valid option."
|
|
STDERR.puts parser
|
|
exit 1
|
|
end
|
|
|
|
parser.unknown_args do |x|
|
|
args = x
|
|
|
|
if args.size < 1
|
|
puts parser
|
|
exit 1
|
|
end
|
|
end
|
|
end
|
|
|
|
command = args[0]
|
|
|
|
storage = Storage.new
|
|
|
|
enum Tap::Entry::Status
|
|
def to_s
|
|
if self == NotOk
|
|
"not ok"
|
|
elsif self == Ok
|
|
"ok"
|
|
end
|
|
end
|
|
end
|
|
|
|
case command
|
|
when "add"
|
|
if args.size != 4
|
|
STDERR.puts "usage: tap-aggregator add <project> <environment> <revision> [options]"
|
|
exit 1
|
|
end
|
|
|
|
project = args[1]
|
|
environment = args[2]
|
|
revision = args[3]
|
|
|
|
storage.store project, environment, revision, STDIN.gets_to_end
|
|
when "show"
|
|
projects = storage.projects.select do |project|
|
|
show_projects.size == 0 || show_projects.any? &.==(project)
|
|
end
|
|
|
|
projects.each do |project|
|
|
environments = storage.environments(project).select do |environment|
|
|
show_environments.size == 0 || show_environments.any? &.==(environment)
|
|
end
|
|
|
|
environments.each do |environment|
|
|
# FIXME: This currently parses everything, including entries
|
|
# that are not going to be displayed.
|
|
results = storage.results(project, environment).select do |revision, timestamp, suite|
|
|
show_revisions.size == 0 || show_revisions.any? &.==(revision)
|
|
end
|
|
|
|
results.each do |revision, timestamp, suite|
|
|
# FIXME: Only extract most recent revision if show_as_summary.
|
|
summary = suite.summary
|
|
number_ok = summary.tests_passed.size
|
|
number_failed = summary.tests_failed.size
|
|
|
|
# This prints the header, or summary line of a test suite.
|
|
STDOUT << ("%-15s" % project).colorize(:white).bright
|
|
STDOUT << " (#{environment}) r=#{revision}, "
|
|
|
|
STDOUT << "#{number_ok} ok".colorize(:green).bright
|
|
STDOUT << ", "
|
|
STDOUT << "#{number_failed} not ok".colorize(:red).bright
|
|
STDOUT << "\n"
|
|
|
|
if !show_as_summary
|
|
suite.each do |test|
|
|
# This prints a single TAP test entry.
|
|
STDOUT << " -> "
|
|
STDOUT << ("%3s" % test.id).colorize(:cyan)
|
|
|
|
if test.status.ok?
|
|
STDOUT << (" %6s " % test.status.to_s).colorize(:green)
|
|
else
|
|
STDOUT << (" %6s " % test.status.to_s).colorize(:red)
|
|
end
|
|
STDOUT << test.title.colorize(:white)
|
|
STDOUT << "\n"
|
|
STDOUT.flush
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|