/usr/bin/lintian-junit-report is in jenkins-debian-glue 0.18.4.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | #!/usr/bin/env ruby
# Purpose: run Debian package checks using lintian and report in JUnit format
################################################################################
# Notes:
# * for JUnit spec details see http://windyroad.org/dl/Open%20Source/JUnit.xsd
#
# Ideas:
# * integrate within Jenkins plugin (using jruby)
# * integrate in Violations plugin (for further reporting options)
# git://github.com/jenkinsci/violations-plugin.git
################################################################################
require 'shellwords'
### cmdline parsing {{{
require 'optparse'
options = {}
lintian_options = []
# default
lintian_file = "lintian.txt"
o = OptionParser.new do|opts|
opts.banner = "Usage: #{$0} [<options>] <debian_package_file(s)>"
options[:warnings] = false
opts.on( '-w', '--warnings', 'Output lintian errors *AND* warnings' ) do
options[:warnings] = true
end
options[:disablenotes] = false
opts.on('--disable-notes', 'Disable verbose lintian output' ) do
options[:disablenotes] = true
end
opts.on("--filename <filename>", String, "Write lintian output to <filename> (defaults to lintian.txt)") do |f|
lintian_file = f
end
options[:disableplaintext] = false
opts.on('--disable-plaintext', 'Disable recording lintian output in lintian.txt' ) do
options[:disableplaintext] = true
end
opts.on('--lintian-opt=OPTION', 'Pass OPTION to lintian. Can be given multiple times.') do |lo|
lintian_options << lo
end
opts.on('--mark-warnings-skipped',
'Mark warnings as skipped test cases.') do
options[:markwarningsskipped] = true
end
opts.on('--mark-as-skipped=tag1,tag2,...', Array,
'Mark selected tags as skipped.') do |l|
options[:markasskipped] = l
end
opts.on( '-h', '--help', 'Display this screen' ) do
puts opts
exit
end
end
begin o.parse! ARGV
rescue OptionParser::InvalidOption => e
puts e
puts o
exit(1)
end
# brrr!
def usage
$stderr.puts "Usage: #{$0} [<options>] <debian_package_file(s)>"
exit(1)
end
files = ARGV
usage if files.empty?
### }}}
### make sure lintian is available {{{
if not system("which lintian >/dev/null 2>&1") then
$stderr.puts "Error: lintian not available."
exit(1)
end
# }}}
### run lintian {{{
start = Time.now.to_f
lintian_options << "--info" unless options[:disablenotes]
# Ruby 1.8's IO.popen expects a string instead of an array :(
lintian_cmd = (['lintian'] + lintian_options + files).collect { |v| Shellwords.escape(v) }.join(" ")
$output = IO.popen(lintian_cmd) do |io|
io.read
end
$duration = Time.now.to_f - start
if ! options[:disablenotes] then
File.open(lintian_file, 'w') {|f| f.write($output) }
end
### }}}
class JUnitOutput
require 'rexml/formatters/transitive'
require 'rexml/document'
def initialize(duration)
@duration = duration
@document = REXML::Document::new
@document << REXML::XMLDecl::new
@failures = 0
@skipped = 0
@suite = @document.add_element 'testsuite', {'time' => duration}
end
def add_case(package, tag)
tc = @suite.add_element 'testcase'
tc.attributes['name'] = "#{tag}"
tc.attributes['classname'] = "lintian.#{package}"
tc.attributes['assertions'] = 0
@last_tag = tag
@last_package = package
end
def mark(kind, message)
tc = @suite[-1]
e = tc.add_element kind
e.attributes['type'] = @last_tag
e.attributes['message'] = message
end
def mark_skipped(message = '')
@skipped += 1
mark('skipped', message)
end
def mark_failure(message = '')
@failures += 1
mark('failure', message)
end
def append_stdout(s)
stdout = @suite[-1].get_elements('system-out')[0]
stdout ||= @suite[-1].add_element 'system-out'
stdout.add_text(s)
end
def add_success
self.add_case('<all>', 'lintian-checks')
end
def finish
self.add_success unless @suite.has_elements?
tc_time = @duration / @suite.size
@suite.each { |tc| tc.attributes['time'] = tc_time }
@suite.attributes['tests'] = @suite.size
@suite.attributes['failures'] = @failures
@suite.attributes['skipped'] = @skipped
@suite.attributes['errors'] = 0
@suite.attributes['assertions'] = 0
end
def write
self.finish
formatter = REXML::Formatters::Transitive::new
formatter.write(@document, $stdout)
end
end
junit_output = JUnitOutput::new($duration)
infos = Hash.new { |hash, key| hash[key] = "" }
last_tag = nil
tc_open = false
$output.each_line do |line|
case line
when /^([EW]):\s([^:]*):\s(.*)/
kind, package, note = $~.captures
if tc_open then
junit_output.append_stdout(infos[last_tag])
tc_open = false
end
tag = note.match('^[^\s]*')[0]
if kind == 'E' || options[:warnings] then
junit_output.add_case(package, note)
if (kind == 'W' && options[:markwarningsskipped]) ||
(options[:markasskipped] && options[:markasskipped].include?(tag))
junit_output.mark_skipped(line.rstrip)
else
junit_output.mark_failure(line.rstrip)
end
tc_open = true
end
last_tag = tag
# Tag descriptions are prefixed with four spaces, which differentiates them
# from debug messages
when /^N:\s{4}/
infos[last_tag] << line if last_tag
end
end
junit_output.append_stdout(infos[last_tag]) if tc_open
junit_output.write
### }}}
## END OF FILE #################################################################
# vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2 ft=ruby
|