Class: Lcoveralls::Runner
- Inherits:
-
Object
- Object
- Lcoveralls::Runner
- Defined in:
- lib/lcoveralls/runner.rb
Overview
Runs the Lcoveralls application.
Instance Method Summary collapse
-
#find_root(info_files) ⇒ String?
Attempts to auto-detect the git repository root.
-
#get_git_info(root_dir) ⇒ Hash
Get git repository information in the Coveralls API structure.
-
#get_percentage(lines_hit, lines_found, bold = false) ⇒ String
Format a percentage string.
-
#get_source_files(info_files, root_dir) ⇒ Hash
Builds a hash of source files matching the Coveralls API.
-
#initialize ⇒ Runner
constructor
Initializes a new Locveralls::Runner instance.
-
#run ⇒ Object
Runs the Lcoveralls application.
-
#should_retry? ⇒ Boolean
Should we retry a failed Coveralls API request?.
Constructor Details
#initialize ⇒ Runner
Initializes a new Locveralls::Runner instance.
26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/lcoveralls/runner.rb', line 26 def initialize # Parse the command line options. parser = Lcoveralls::OptionParser.new @options = parser.parse! ARGV # Setup a logger instance. @log = Logger.new(STDERR) @log.formatter = Lcoveralls::ColorFormatter.new @options[:color] @log.sev_threshold = @options[:severity] @log.debug { "Options: #{@options}" } end |
Instance Method Details
#find_root(info_files) ⇒ String?
Attempts to auto-detect the git repository root.
This method looks throuhgh all source files covered by the supplied tracefiles, and for each, check if they are part of a git repository. The method then returns git repository’s root directory.
If more than one git repository are found to be covered by the tracefiles then a warning will be logged, and the root of the repository with the largest number of source files covered will be returned.
If no git repository roots could be found, then nil is returned.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/lcoveralls/runner.rb', line 53 def find_root(info_files) # Try source file(s) covered by the lcov tracefile(s). root_dirs = Hash.new(0) info_files.each do |file| File.open(file).each do |line| line.match(/^SF:(.*)$/) do |match| Dir.chdir(File.dirname(match[1])) do root_dir = `"#{@options[:git]}" rev-parse --show-toplevel`.rstrip root_dirs[root_dir] = root_dirs[root_dir] + 1 unless root_dir.empty? end if Dir.exist?(File.dirname(match[1])) end end end if root_dirs.empty? nil elsif root_dirs.size == 1 root_dirs.shift[0] else root_dir = root_dirs.max_by { |key, value| value }[0] @log.warn "Found multiple possible repo roots; settled on: #{root_dir}" root_dir end end |
#get_git_info(root_dir) ⇒ Hash
Get git repository information in the Coveralls API structure.
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 |
# File 'lib/lcoveralls/runner.rb', line 183 def get_git_info(root_dir) Dir.chdir(root_dir) do info = { :head => { :id => `"#{@options[:git]}" show --format='%H' --no-patch`.rstrip, :author_name => `"#{@options[:git]}" show --format='%an' --no-patch`.rstrip, :author_email => `"#{@options[:git]}" show --format='%ae' --no-patch`.rstrip, :commiter_name => `"#{@options[:git]}" show --format='%cn' --no-patch`.rstrip, :commiter_email => `"#{@options[:git]}" show --format='%ce' --no-patch`.rstrip, :message => `"#{@options[:git]}" show --format='%B' --no-patch`.rstrip, }, :branch => `"#{@options[:git]}" rev-parse --abbrev-ref HEAD`.rstrip, :remotes => [] } `"#{@options[:git]}" remote --verbose`.each_line do |line| line.match(/^(?<name>\S+)\s+(?<url>\S+)(\s+\((fetch|push)\))?/) do |match| info[:remotes] << Hash[match.names.zip(match.captures)] end end info[:remotes].uniq! info.delete(:remotes) if info[:remotes].empty? info end if Dir.exist?(root_dir) end |
#get_percentage(lines_hit, lines_found, bold = false) ⇒ String
Format a percentage string.
This method formats the number of lines hit, as a percentage of the total number of lines, including prepended spaces, and color codes where appropriate.
If the percentage cannot be calculated (for example, either parameter is nil, NaN, +/- ininity, etc), then this function will return a ‘blank’ string - one with enough spaces to match the width of other valid percentage strings returned by this function.
93 94 95 96 97 98 99 100 |
# File 'lib/lcoveralls/runner.rb', line 93 def get_percentage(lines_hit, lines_found, bold=false) perc = lines_hit.to_f / lines_found.to_f * 100.0 color = case when perc >= 90; 32 when perc >= 75; 33 else 31 end if bold then color = "1;#{color}" end perc = perc.finite? ? format('%5.1f%%', perc) : ' ' * 6 perc = "\x1b[#{color}m#{perc}\x1b[0m" if @options[:color] and color perc end |
#get_source_files(info_files, root_dir) ⇒ Hash
Builds a hash of source files matching the Coveralls API.
This method will build a Hash containing all source files covered by the supplied LCOV tracefiles, that reside within the specified repository root directory.
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 |
# File 'lib/lcoveralls/runner.rb', line 112 def get_source_files(info_files, root_dir) sources = {} total_lines_found = 0 total_lines_hit = 0 info_files.each do |file| @log.debug "Processing tracefile: #{file}" source_pathname = nil in_record = false lines_found = nil lines_hit = nil File.open(file).each do |line| @log.debug "#{file}: #{line.rstrip}" # SF:<absolute path to the source file> line.match('^SF:' + Regexp.quote(root_dir) + '/(.*)$') do |match| @log.warn 'Found source filename without preceding end_of_record' if in_record @log.debug "Found source filename: #{match[1]}" source_pathname = match[1] if !sources.has_key?(source_pathname) then source = File.read(match[1]) sources[source_pathname] = { :name => source_pathname, :source => source, :coverage => Array.new(source.lines.count) } end in_record = true end # DA:<line number>,<execution count>[,<checksum>] line.match(/^DA:(?<line>\d+),(?<count>\d+)(,(?<checksum>.*))?$/) do |match| line_index = match[:line].to_i - 1 if !sources[source_pathname][:coverage][line_index] then sources[source_pathname][:coverage][line_index] = 0 end sources[source_pathname][:coverage][line_index] = sources[source_pathname][:coverage][line_index] + match[:count].to_i; end if in_record # LF:<lines found> or LH:<lines hit> line.match(/^LF:(?<count>\d+)$/) { |match| lines_found = match[:count] } line.match(/^LH:(?<count>\d+)$/) { |match| lines_hit = match[:count] } # end_of_record if line == "end_of_record\n" and in_record then @log.info begin perc = get_percentage(lines_hit, lines_found) "[#{perc}] #{source_pathname} (#{lines_hit}/#{lines_found})" end total_lines_found = total_lines_found + lines_found.to_i total_lines_hit = total_lines_hit + lines_hit.to_i in_record = false lines_found = nil lines_hit = nil end end end @log.info begin perc = get_percentage(total_lines_hit, total_lines_found, true) "[#{perc}] Total (#{total_lines_hit}/#{total_lines_found})" end sources.values end |
#run ⇒ Object
Runs the Lcoveralls application.
This method does the real work of building up the Coveralls API request according to the parsed options, and submitting the request to Coveralls.
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
# File 'lib/lcoveralls/runner.rb', line 241 def run # Find *.info tracefiles if none specified on the command line. Find.find('.') do |path| @log.trace { "Looking for tracefiles: #{path}" } if path =~ /.*\.info$/ then @log.info { "Found tracefile: #{path}" } ARGV << path end end unless ARGV.any? @options[:root] = find_root(ARGV) unless @options.include?(:root) if !@options[:root] then @log.error 'Root not specified, nor detected; consider using --root' exit! end # Build the coveralls.io job request. job = {} job[:repo_token] = @options[:token] if @options.has_key? :token job[:service_name] = @options[:service] if @options.has_key? :service job[:service_job_id] = @options[:job_id] if @options.has_key? :job_id if !job.has_key?(:token) and !job.has_key?(:service_job_id) then @log.warn 'No service job id detected; consider using --token' end job[:source_files] = get_source_files(ARGV, @options[:root]) job[:git] = get_git_info(@options[:root]) unless !@options[:git] job[:run_at] = Time.new request = Lcoveralls::CoverallsRequest.new(job) @log.trace { request.body } # If asked to, export the Coveralls API job request JSON document. if @options.has_key? :export then @options[:export].write(JSON::pretty_generate job); end # Send (if not in dryrun mode) the Coveralls API request. uri = URI('https://coveralls.io/api/v1/jobs') http = Net::HTTP.new(uri.host, uri.port) http.open_timeout = @options[:timeout] if @options.has_key? :timeout http.read_timeout = @options[:timeout] if @options.has_key? :timeout http.ssl_timeout = @options[:timeout] if @options.has_key? :timeout http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_PEER if !@options[:dryrun] then begin @log.debug { "Sending #{request.body.size} bytes to coveralls.io" } response = http.request(request) @log.debug { "HTTP response status: #{response.code} #{response.}" } raise response.code unless response.is_a? Net::HTTPSuccess puts response.body rescue RuntimeError raise unless response @log.error { "Received non-OK response: #{response.code} #{response.}" } puts response.body retry if should_retry? unless response.is_a? Net::HTTPClientError exit! rescue SocketError => error @log.error { error } retry if should_retry? exit! end end end |
#should_retry? ⇒ Boolean
Should we retry a failed Coveralls API request?
This method is called by #run on internal and server errors to check if the API request should be retried. Specifically, this function checks the :retry_count option, and if greater than zero decrements it before returning true.
Additionally, if retrying is appropriate, and the :retry_interval option is greater than zero, this function will also sleep for that interval.
222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/lcoveralls/runner.rb', line 222 def should_retry? return false unless @options[:retry_count] > 0 @options[:retry_count] = @options[:retry_count] - 1; if @options[:retry_interval] > 0 then @log.info { "Sleeping for #{@options[:retry_interval]} seconds before retrying" } begin sleep @options[:retry_interval] rescue Interrupt return false end end true end |