Class: PotentialBuild
- Inherits:
-
Object
- Object
- PotentialBuild
- Includes:
- CMake, Configuration, Lcov, ResultsProcessor, Runners
- Defined in:
- lib/potentialbuild.rb
Overview
Contains the logic flow for executing builds and parsing results
Instance Attribute Summary collapse
-
#branch_name ⇒ Object
readonly
Returns the value of attribute branch_name.
-
#commit_sha ⇒ Object
readonly
Returns the value of attribute commit_sha.
-
#failure ⇒ Object
Returns the value of attribute failure.
-
#repository ⇒ Object
readonly
Returns the value of attribute repository.
-
#tag_name ⇒ Object
readonly
Returns the value of attribute tag_name.
-
#test_run ⇒ Object
Returns the value of attribute test_run.
Instance Method Summary collapse
- #add_dashes(str) ⇒ Object
- #build_base_name(compiler) ⇒ Object
- #checkout(src_dir) ⇒ Object
- #clone_regression_repository ⇒ Object
- #collect_file_sizes(build_dir: File.absolute_path(this_build_dir)) ⇒ Object
- #collect_perf_results(build_dir: File.absolute_path(this_build_dir)) ⇒ Object
- #collect_valgrind_counters_results(build_dir: File.absolute_path(this_build_dir)) ⇒ Object
- #compilers ⇒ Object
- #configuration ⇒ Object
- #descriptive_string ⇒ Object
- #device_id(compiler) ⇒ Object
- #device_tag(compiler) ⇒ Object
- #do_build(compiler, regression_baseline, is_release = false) ⇒ Object
- #do_coverage(compiler) ⇒ Object
- #do_test(compiler, regression_baseline) ⇒ Object
- #do_upload(compiler) ⇒ Object
- #get_full_build_name(compiler) ⇒ Object
- #get_initials(str) ⇒ Object
- #get_short_form(str) ⇒ Object
-
#initialize(client, token, repository, tag_name, commit_sha, branch_name, author, release_url, release_assets, pull_id, pr_base_repository, pr_base_ref) ⇒ PotentialBuild
constructor
rubocop:disable Metrics/ParameterLists.
- #needs_regression_test(compiler) ⇒ Object
- #needs_run(compiler) ⇒ Object
- #next_build ⇒ Object
- #parse_callgrind(build_dir, file) ⇒ Object
- #parse_file_sizes(file) ⇒ Object
- #parse_perf(file) ⇒ Object
- #post_results(compiler, pending) ⇒ Object
- #pull_request? ⇒ Boolean
- #release? ⇒ Boolean
- #results_file_name(compiler) ⇒ Object
- #set_as_baseline ⇒ Object
- #short_build_base_name(compiler) ⇒ Object
- #this_branch_folder ⇒ Object
- #this_build_dir ⇒ Object
- #this_regression_dir ⇒ Object
- #this_src_dir ⇒ Object
- #try_to_repost_asset(response, asset_name) ⇒ Object
Methods included from Runners
#monitor_thread_state, #read_state_singular, #run_scripts, #run_single_script, #run_with_timeout
Methods included from Lcov
#generate_base_command_line, #generate_filter_command_line, #generate_html_command_line, #lcov
Methods included from ResultsProcessor
#get_win32_filename, #match_type_to_possible_fortran, #parse_error_messages, #parse_gcc_line, #parse_generic_line, #parse_msvc_line, #parse_python_or_latex_line, #process_cmake_results, #process_ctest_results, #process_gcc_results, #process_lcov_results, #process_msvc_results, #process_python_results, #recover_file_case, #relative_path
Methods included from Configuration
#_setup_cc_and_cxx, #establish_base_configuration, #establish_os_characteristics, #establish_windows_characteristics, #find_valid_yaml_files, #get_all_yaml_names, #load_configuration, #load_yaml, #setup_compiler_architecture, #setup_compiler_build_generator, #setup_compiler_description, #setup_compiler_extra_flags, #setup_compiler_num_processors, #setup_compiler_target_arch, #setup_compiler_version, #setup_gcc_style_cc_and_cxx, #setup_single_compiler, #symbolize, #which
Methods included from CMake
#cmake_build, #cmake_remove_git_from_path, #cmake_test
Constructor Details
#initialize(client, token, repository, tag_name, commit_sha, branch_name, author, release_url, release_assets, pull_id, pr_base_repository, pr_base_ref) ⇒ PotentialBuild
rubocop:disable Metrics/ParameterLists
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 |
# File 'lib/potentialbuild.rb', line 36 def initialize(client, token, repository, tag_name, commit_sha, branch_name, , release_url, release_assets, # rubocop:disable Metrics/ParameterLists pull_id, pr_base_repository, pr_base_ref) @client = client @config = load_configuration(repository, (tag_name.nil? ? commit_sha : tag_name), !release_url.nil?) @config.repository_name = github_query(@client) { @client.repo(repository).name } @config.repository = repository @config.token = token @repository = repository @tag_name = tag_name @commit_sha = commit_sha @branch_name = branch_name @release_url = release_url @release_assets = release_assets @author = @buildid = @tag_name || @commit_sha @refspec = @tag_name || @branch_name @pull_id = pull_id @pull_request_base_repository = pr_base_repository @pull_request_base_ref = pr_base_ref @short_buildid = get_short_form(@tag_name) || @commit_sha[0..9] unless @pull_id.nil? @buildid = "#{@buildid}-PR#{@pull_id}" @short_buildid = "#{@short_buildid}-PR#{@pull_id}" end @package_locations = nil @test_results = nil @test_messages = [] @build_results = SortedSet.new @package_results = SortedSet.new @dateprefix = nil @failure = nil @test_run = false @build_time = nil @test_time = nil @install_time = nil @package_time = nil @coverage_lines = 0 @coverage_total_lines = 0 @coverage_functions = 0 @coverage_total_functions = 0 @coverage_url = nil @asset_url = nil @acting_as_baseline = false @valgrind_counters_results = nil @perf_counters_results = nil @file_sizes = nil end |
Instance Attribute Details
#branch_name ⇒ Object (readonly)
Returns the value of attribute branch_name
33 34 35 |
# File 'lib/potentialbuild.rb', line 33 def branch_name @branch_name end |
#commit_sha ⇒ Object (readonly)
Returns the value of attribute commit_sha
33 34 35 |
# File 'lib/potentialbuild.rb', line 33 def commit_sha @commit_sha end |
#failure ⇒ Object
Returns the value of attribute failure
34 35 36 |
# File 'lib/potentialbuild.rb', line 34 def failure @failure end |
#repository ⇒ Object (readonly)
Returns the value of attribute repository
33 34 35 |
# File 'lib/potentialbuild.rb', line 33 def repository @repository end |
#tag_name ⇒ Object (readonly)
Returns the value of attribute tag_name
33 34 35 |
# File 'lib/potentialbuild.rb', line 33 def tag_name @tag_name end |
#test_run ⇒ Object
Returns the value of attribute test_run
34 35 36 |
# File 'lib/potentialbuild.rb', line 34 def test_run @test_run end |
Instance Method Details
#add_dashes(str) ⇒ Object
239 240 241 |
# File 'lib/potentialbuild.rb', line 239 def add_dashes(str) str.gsub(/([0-9]{3,})([A-Z])/, '\1-\2').gsub(/([A-Z])([0-9]{3,})/, '\1-\2') end |
#build_base_name(compiler) ⇒ Object
120 121 122 |
# File 'lib/potentialbuild.rb', line 120 def build_base_name(compiler) "#{@config.repository_name}-#{@buildid}-#{device_id(compiler)}" end |
#checkout(src_dir) ⇒ Object
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 |
# File 'lib/potentialbuild.rb', line 132 def checkout(src_dir) # TODO: update this to be a merge, not just a checkout of the pull request branch FileUtils.mkdir_p src_dir if @pull_id.nil? $logger.info("Checking out branch \"#{@refspec}\"") _, _, result = run_scripts( @config, [ "cd #{src_dir} && git init", "cd #{src_dir} && git pull https://#{@config.token}@github.com/#{@repository} \"#{@refspec}\"" ] ) success = !@commit_sha.nil? && @commit_sha != '' && result.zero? _, _, result = run_scripts(@config, ["cd #{src_dir} && git checkout #{@commit_sha}"]) if success else $logger.info("Checking out PR \"#{@pull_id}\"") _, _, result = run_scripts( @config, [ "cd #{src_dir} && git init", "cd #{src_dir} && git pull https://#{@config.token}@github.com/#{@pull_request_base_repository} refs/pull/#{@pull_id}/head", "cd #{src_dir} && git checkout FETCH_HEAD" ] ) end result.zero? end |
#clone_regression_repository ⇒ Object
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
# File 'lib/potentialbuild.rb', line 318 def clone_regression_repository regression_dir = this_regression_dir FileUtils.mkdir_p regression_dir return if @config.regression_repository.nil? if !@config.regression_commit_sha.nil? && @config.regression_commit_sha != '' refspec = @config.regression_commit_sha elsif !@config.regression_branch.nil? && @config.regression_branch != '' refspec = @config.regression_branch else $logger.debug('No regression repository checkout info!?!') return end run_scripts( @config, [ "cd #{regression_dir} && git init", "cd #{regression_dir} && git fetch https://#{@config.token}@github.com/#{@config.regression_repository} #{refspec}", "cd #{regression_dir} && git checkout FETCH_HEAD" ] ) end |
#collect_file_sizes(build_dir: File.absolute_path(this_build_dir)) ⇒ Object
493 494 495 496 497 498 499 500 501 502 503 504 |
# File 'lib/potentialbuild.rb', line 493 def collect_file_sizes(build_dir: File.absolute_path(this_build_dir)) results = [] Dir["#{build_dir}/**/size.*"].each do |file| file_name = file.sub(/.*size\./, '') $logger.info("Parsing #{file}") sizes = parse_file_sizes(file) sizes['file_name'] = file_name results << sizes end @file_sizes = results end |
#collect_perf_results(build_dir: File.absolute_path(this_build_dir)) ⇒ Object
506 507 508 509 510 511 512 513 514 515 516 517 518 |
# File 'lib/potentialbuild.rb', line 506 def collect_perf_results(build_dir: File.absolute_path(this_build_dir)) results = { 'test_files' => [] } Dir["#{build_dir}/**/perf.*"].each do |file| perf_counters_test_name = file.sub(/.*perf\./, '') $logger.info("Parsing #{file}") perf_output = parse_perf(build_dir, file) perf_output['test_name'] = perf_counters_test_name results['test_files'] << perf_output end @perf_counters_results = results end |
#collect_valgrind_counters_results(build_dir: File.absolute_path(this_build_dir)) ⇒ Object
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 |
# File 'lib/potentialbuild.rb', line 520 def collect_valgrind_counters_results(build_dir: File.absolute_path(this_build_dir)) results = { 'object_files' => [], 'test_files' => [] } Dir["#{build_dir}/**/callgrind.*"].each do |file| valgrind_counters_test_name = file.sub(/.*callgrind\./, '') callgrind_output = parse_callgrind(build_dir, file) object_files = callgrind_output.delete('object_files') $logger.info("Object files: #{object_files}") results['object_files'].concat(object_files) callgrind_output['test_name'] = valgrind_counters_test_name results['test_files'] << callgrind_output end results['object_files'].uniq! @valgrind_counters_results = results end |
#compilers ⇒ Object
93 94 95 |
# File 'lib/potentialbuild.rb', line 93 def compilers @config.compilers end |
#configuration ⇒ Object
163 164 165 |
# File 'lib/potentialbuild.rb', line 163 def configuration @config end |
#descriptive_string ⇒ Object
97 98 99 |
# File 'lib/potentialbuild.rb', line 97 def descriptive_string "#{@commit_sha} #{@branch_name} #{@tag_name} #{@buildid}" end |
#device_id(compiler) ⇒ Object
116 117 118 |
# File 'lib/potentialbuild.rb', line 116 def device_id(compiler) "#{compiler[:architecture]}-#{@config.os}-#{@config.os_release}-#{compiler[:description]}#{device_tag(compiler)}" end |
#device_tag(compiler) ⇒ Object
109 110 111 112 113 114 |
# File 'lib/potentialbuild.rb', line 109 def device_tag(compiler) build_type_tag = '' build_type_tag = "-#{compiler[:build_tag]}" unless compiler[:build_tag].nil? build_type_tag = "#{build_type_tag}-#{compiler[:build_type]}" if compiler[:build_type] !~ /release/i build_type_tag end |
#do_build(compiler, regression_baseline, is_release = false) ⇒ Object
283 284 285 286 287 288 289 290 291 292 293 294 295 |
# File 'lib/potentialbuild.rb', line 283 def do_build(compiler, regression_baseline, is_release = false) src_dir = this_src_dir build_dir = this_build_dir start_time = Time.now checkout_succeeded = checkout src_dir # TODO: Abort if checkout did not succeed... this_device_id = device_id compiler args = CMakeBuildArgs.new(compiler[:build_type], this_device_id, is_release) cmake_build compiler, src_dir, build_dir, this_regression_dir, regression_baseline, args if checkout_succeeded @build_time = 0 if @build_time.nil? @build_time += (Time.now - start_time) # TODO: Should we return true here? end |
#do_coverage(compiler) ⇒ Object
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/potentialbuild.rb', line 167 def do_coverage(compiler) return nil unless compiler[:coverage_enabled] $logger.info("Beginning coverage calculation phase #{release?}") build_dir = this_build_dir @coverage_total_lines, @coverage_lines, @coverage_total_functions, @coverage_functions = lcov @config, compiler, build_dir return if compiler[:coverage_s3_bucket].nil? s3_script = "#{File.dirname(File.dirname(__FILE__))}/send_to_s3.py" $logger.info('Beginning upload of coverage results to s3') out, = run_scripts( @config, [ "#{s3_script} #{compiler[:coverage_s3_bucket]} #{get_full_build_name(compiler)} #{build_dir}/lcov-html coverage" ] ) @coverage_url = out out end |
#do_test(compiler, regression_baseline) ⇒ Object
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
# File 'lib/potentialbuild.rb', line 297 def do_test(compiler, regression_baseline) src_dir = this_src_dir build_dir = this_build_dir build_succeeded = do_build compiler, regression_baseline start_time = Time.now if ENV['DECENT_CI_SKIP_TEST'] $logger.debug('Skipping test, DECENT_CI_SKIP_TEST is set in the environment') elsif build_succeeded cmake_test compiler, src_dir, build_dir, compiler[:build_type] end @test_time = 0 if @test_time.nil? # handle the case where test is called more than once @test_time += (Time.now - start_time) end |
#do_upload(compiler) ⇒ Object
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/potentialbuild.rb', line 191 def do_upload(compiler) return nil if compiler[:s3_upload].nil? $logger.info("Beginning upload phase #{release?} #{!compiler[:s3_upload].nil?}") build_dir = this_build_dir s3_script = "#{File.dirname(File.dirname(__FILE__))}/send_to_s3.py" $logger.info('Beginning upload of build assets to s3') out, = run_scripts( @config, [ "#{s3_script} #{compiler[:s3_upload_bucket]} #{get_full_build_name(compiler)} #{build_dir}/#{compiler[:s3_upload]} assets" ] ) @asset_url = out out end |
#get_full_build_name(compiler) ⇒ Object
263 264 265 |
# File 'lib/potentialbuild.rb', line 263 def get_full_build_name(compiler) "#{get_short_form(@config.repository_name)}-#{@short_buildid}-#{compiler[:architecture]}-#{get_short_form(compiler[:description])}#{get_short_form(device_tag(compiler))}" end |
#get_initials(str) ⇒ Object
234 235 236 237 |
# File 'lib/potentialbuild.rb', line 234 def get_initials(str) # extracts just the initials from the string str.gsub(/[^A-Z0-9.\-a-z_+]/, '').gsub(/[_\-+]./) { |s| s[1].upcase }.sub(/./, &:upcase).gsub(/[^A-Z0-9.]/, '') end |
#get_short_form(str) ⇒ Object
243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/potentialbuild.rb', line 243 def get_short_form(str) return nil if str.nil? if str.length <= 10 && str =~ /[a-zA-Z]/ str elsif (str =~ /.*[A-Z].*/ && str =~ /.*[a-z].*/) || str =~ /.*_.*/ || str =~ /.*-.*/ || str =~ /.*\+.*/ add_dashes(get_initials(str)) else str.gsub(/[^a-zA-Z0-9.+_]/, '') end end |
#needs_regression_test(compiler) ⇒ Object
314 315 316 |
# File 'lib/potentialbuild.rb', line 314 def needs_regression_test(compiler) (!@config.regression_script.nil? || !@config.regression_repository.nil?) && !ENV['DECENT_CI_SKIP_REGRESSIONS'] && !compiler[:skip_regression] end |
#needs_run(compiler) ⇒ Object
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/potentialbuild.rb', line 213 def needs_run(compiler) return true if @test_run file_names = [] begin files = github_query(@client) { @client.content @config.results_repository, :path => "#{@config.results_path}/#{this_branch_folder}" } files.each do |f| file_names << f.name end rescue Octokit::NotFound # rubocop:disable Lint/SuppressedException # repository doesn't have a _posts folder yet end file_names.each do |f| return false if f.end_with? results_file_name(compiler) end true end |
#next_build ⇒ Object
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
# File 'lib/potentialbuild.rb', line 341 def next_build @package_locations = nil @test_results = nil @test_messages = [] @build_results = SortedSet.new @package_results = SortedSet.new @dateprefix = nil @failure = nil @build_time = nil @test_time = nil @test_run = false @package_time = nil @install_time = nil @valgrind_counters_results = nil @perf_counters_results = nil @file_sizes = nil @coverage_lines = 0 @coverage_total_lines = 0 @coverage_functions = 0 @coverage_total_functions = 0 @coverage_url = nil @asset_url = nil @acting_as_baseline = false end |
#parse_callgrind(build_dir, file) ⇒ Object
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
# File 'lib/potentialbuild.rb', line 397 def parse_callgrind(build_dir, file) object_files = {} source_files = {} functions = {} props = {} get_name = lambda do |files, id, name| if name.nil? || name == '' return_value = files[id] elsif id.nil? return_value = name else files[id] = name return_value = name end return_value end object_file = nil source_file = nil call_count = nil called_object_file = nil called_source_file = nil called_function_name = nil called_functions = {} IO.foreach(file) do |line| if /^(?<field>[a-z]+): (?<data>.*)/ =~ line if field == 'totals' totals = data.split props['totals'] = totals[0].to_i if totals.size == 5 props['conditional_branches'] = totals[1].to_i props['conditional_branches_missses'] = totals[2].to_i props['indirect_jumps'] = totals[3].to_i props['indirect_jump_misses'] = totals[4].to_i end else props[field] = data end elsif /^ob=(?<objectfileid>\([0-9]+\))?\s*(?<objectfilename>.*)?/ =~ line object_file = get_name.call(object_files, objectfileid, objectfilename) elsif /^fl=(?<sourcefileid>\([0-9]+\))?\s*(?<sourcefilename>.*)?/ =~ line source_file = get_name.call(source_files, sourcefileid, sourcefilename) elsif /^(fe|fi)=(?<sourcefileid>\([0-9]+\))?\s*(?<sourcefilename>.*)?/ =~ line get_name.call(source_files, sourcefileid, sourcefilename) elsif /^fn=(?<functionid>\([0-9]+\))?\s*(?<functionname>.*)?/ =~ line get_name.call(functions, functionid, functionname) elsif /^cob=(?<calledobjectfileid>\([0-9]+\))?\s*(?<calledobjectfilename>.*)?/ =~ line called_object_file = get_name.call(object_files, calledobjectfileid, calledobjectfilename) elsif /^(cfi|cfl)=(?<calledsourcefileid>\([0-9]+\))?\s*(?<calledsourcefilename>.*)?/ =~ line called_source_file = get_name.call(source_files, calledsourcefileid, calledsourcefilename) elsif /^cfn=(?<calledfunctionid>\([0-9]+\))?\s*(?<calledfunctionname>.*)?/ =~ line called_function_name = get_name.call(functions, calledfunctionid, calledfunctionname) elsif /^calls=(?<count>[0-9]+)?\s+(?<target_position>[0-9]+)/ =~ line # rubocop:disable Lint/UselessAssignment call_count = count elsif /^(?<subposition>(((\+|-)?[0-9]+)|\*)) (?<cost>[0-9]+)/ =~ line # rubocop:disable Lint/UselessAssignment unless call_count.nil? this_object_file = called_object_file.nil? ? object_file : called_object_file this_source_file = called_source_file.nil? ? source_file : called_source_file called_func_is_nil = called_functions[[this_object_file, this_source_file, called_function_name]].nil? called_functions[[this_object_file, this_source_file, called_function_name]] = { 'count' => 0, 'cost' => 0 } if called_func_is_nil called_functions[[this_object_file, this_source_file, called_function_name]]['count'] += call_count.to_i called_functions[[this_object_file, this_source_file, called_function_name]]['cost'] += cost.to_i call_count = nil called_object_file = nil called_source_file = nil called_function_name = nil end # elsif line == "\n" end end props['object_files'] = [] object_files.each_value do |this_file| abs_path = File.absolute_path(this_file, build_dir) next unless abs_path.start_with?(File.absolute_path(build_dir)) && File.exist?(abs_path) # is in subdir? $logger.info("Path: #{abs_path} build_dir #{build_dir}") props['object_files'] << { 'name' => Pathname.new(abs_path).relative_path_from(Pathname.new(build_dir)).to_s, 'size' => File.size(abs_path) } end most_expensive = called_functions.sort_by { |_, v| v['cost'] }.reverse.slice(0, 50) most_called = called_functions.sort_by { |_, v| v['count'] }.reverse.slice(0, 50) important_functions = most_expensive.to_h.merge(most_called.to_h).collect { |k, v| { 'object_file' => k[0], 'source_file' => k[1], 'function_name' => k[2] }.merge(v) } props.merge('data' => important_functions) end |
#parse_file_sizes(file) ⇒ Object
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
# File 'lib/potentialbuild.rb', line 366 def parse_file_sizes(file) props = {} names = nil IO.foreach(file) do |line| if names.nil? names = line.split else values = line.split values.each_index do |index| props[names[index]] = values[index] end end end props end |
#parse_perf(file) ⇒ Object
386 387 388 389 390 391 392 393 394 395 |
# File 'lib/potentialbuild.rb', line 386 def parse_perf(file) props = {} IO.foreach(file) do |line| values = line.split(',') props[values[2]] = values[0].to_i if values.size > (3) && (values[0] != '<not supported>' && values[0] != '') end props end |
#post_results(compiler, pending) ⇒ Object
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 |
# File 'lib/potentialbuild.rb', line 572 def post_results(compiler, pending) @dateprefix = DateTime.now.utc.strftime('%F') if @dateprefix.nil? test_results_data = [] test_results_passed = 0 test_results_total = 0 test_results_warning = 0 test_results_failure_counts = {} @test_results&.each do |t| test_results_total += 1 test_results_passed += 1 if t.passed test_results_warning += 1 if t.warning category_index = t.name.index('.') category_name = 'Uncategorized' category_name = t.name.slice(0, category_index) unless category_index.nil? failure_type = t.passed ? 'Passed' : t.failure_type if test_results_failure_counts[category_name].nil? category = {} category.default = 0 test_results_failure_counts[category_name] = category end test_results_failure_counts[category_name][failure_type] += 1 test_results_data << t.inspect end build_errors = 0 build_warnings = 0 build_results_data = [] unless @build_results.nil? begin @build_results.each do |b| build_errors += 1 if b.error? build_results_data << b.inspect end rescue build_errors += 1 build_results_data << { 'message' => 'CI Issue: Error occurred when processing build results on this test' } $logger.warn('Error in processing build_results, maybe a duplicate build_result...?') end build_warnings = @build_results.count - build_errors end package_errors = 0 package_warnings = 0 package_results_data = [] @package_results&.each do |b| package_errors += 1 if b.error? package_warnings += 1 if b.warning? package_results_data << b.inspect end valgrind_counters_total_time = nil valgrind_counters_test_count = 0 valgrind_counters_total_conditional_branches = nil valgrind_counters_total_conditional_branch_misses = nil valgrind_counters_total_indirect_jumps = nil valgrind_counters_total_indirect_jump_misses = nil unless @valgrind_counters_results.nil? valgrind_counters_total_time = 0 valgrind_counters_total_conditional_branches = 0 valgrind_counters_total_conditional_branch_misses = 0 valgrind_counters_total_indirect_jumps = 0 valgrind_counters_total_indirect_jump_misses = 0 @valgrind_counters_results['test_files'].each do |v| valgrind_counters_test_count += 1 valgrind_counters_total_time += v['totals'] unless v['totals'].nil? valgrind_counters_total_conditional_branches += v['conditional_branches'] unless v['conditional_branches'].nil? valgrind_counters_total_conditional_branch_misses += v['conditional_branch_misses'] unless v['conditional_branch_misses'].nil? valgrind_counters_total_indirect_jumps += v['indirect_jumps'] unless v['indirect_jumps'].nil? valgrind_counters_total_indirect_jump_misses += v['indirect_jump_misses'] unless v['indirect_jump_misses'].nil? end end perf_counters = {} unless @perf_counters_results.nil? $logger.debug("perf counters: #{@perf_counters_results}") perf_test_count = 0 @perf_counters_results['test_files'].each do |v| perf_test_count += 1 v.each do |key, value| next if value.is_a? String new_key = "perf_total_#{key}" perf_counters[new_key] = 0 if perf_counters[new_key].nil? $logger.debug("Key: '#{new_key}' value: '#{value}'") perf_counters[new_key] += value end end perf_counters['perf_test_count'] = perf_test_count end package_names_string = nil unless @package_locations.nil? package_names_string = '' @package_locations.each do |location| package_names_string += "; #{Pathname.new(location).basename}" end end yaml_data = { 'title' => build_base_name(compiler), 'permalink' => "#{build_base_name(compiler)}.html", 'tags' => 'data', 'layout' => 'ci_results', 'date' => DateTime.now.utc.strftime('%F %T'), 'unhandled_failure' => !@failure.nil?, 'build_error_count' => build_errors, 'build_warning_count' => build_warnings, 'package_error_count' => package_errors, 'package_warning_count' => package_warnings, 'test_count' => test_results_total, 'test_passed_count' => test_results_passed, 'repository' => @repository, 'compiler' => compiler[:name], 'compiler_version' => compiler[:version], 'architecture' => compiler[:architecture], 'os' => @config.os, 'os_release' => @config.os_release, 'is_release' => release?, 'release_packaged' => !@package_locations.nil?, 'packaging_skipped' => compiler[:skip_packaging], 'package_name' => package_names_string, 'tag_name' => @tag_name, 'commit_sha' => @commit_sha, 'branch_name' => @branch_name, 'test_run' => !@test_results.nil?, 'pull_request_issue_id' => @pull_id.to_s, 'pull_request_base_repository' => @pull_request_base_repository.to_s, 'pull_request_base_ref' => @pull_request_base_ref.to_s, 'device_id' => device_id(compiler), 'pending' => pending, 'build_time' => @build_time, 'test_time' => @test_time, 'package_time' => @package_time, 'install_time' => @install_time, 'results_repository' => @config.results_repository.to_s, 'machine_name' => Socket.gethostname.to_s, 'machine_ip' => Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }.ip_address.to_s, 'test_pass_limit' => @config.test_pass_limit, 'test_warn_limit' => @config.test_warn_limit, 'coverage_enabled' => compiler[:coverage_enabled], 'coverage_pass_limit' => compiler[:coverage_pass_limit], 'coverage_warn_limit' => compiler[:coverage_warn_limit], 'coverage_lines' => @coverage_lines, 'coverage_total_lines' => @coverage_total_lines, 'coverage_functions' => @coverage_functions, 'coverage_total_functions' => @coverage_total_functions, 'coverage_url' => @coverage_url, 'asset_url' => @asset_url, 'performance_total_time' => valgrind_counters_total_time, 'performance_test_count' => valgrind_counters_test_count, 'valgrind_counters_total_time' => valgrind_counters_total_time, 'valgrind_counters_test_count' => valgrind_counters_test_count, 'valgrind_counters_total_conditional_branches' => valgrind_counters_total_conditional_branches, 'valgrind_counters_total_conditional_branch_misses' => valgrind_counters_total_conditional_branch_misses, 'valgrind_counters_total_indirect_jumps' => valgrind_counters_total_indirect_jumps, 'valgrind_counters_total_indirect_jump_misses' => valgrind_counters_total_indirect_jump_misses } yaml_data.merge!(perf_counters) json_data = { 'build_results' => build_results_data, 'test_results' => test_results_data, 'failure' => @failure, 'package_results' => package_results_data, 'configuration' => yaml_data, 'performance_results' => @valgrind_counters_results, 'perf_performance_results' => @perf_counters_results, 'file_sizes' => @file_sizes } json_document = <<-YAML #{yaml_data.to_yaml} --- #{JSON.pretty_generate(json_data)} YAML test_failed = false if @test_results.nil? test_color = 'red' test_failed = true test_string = 'NA' else test_percent = if test_results_total.zero? 100.0 else (test_results_passed.to_f / test_results_total.to_f) * 100.0 end if test_percent > @config.test_pass_limit test_color = 'green' elsif test_percent > @config.test_warn_limit test_color = 'yellow' else test_color = 'red' test_failed = true end test_string = "#{test_percent.round(2)}%25" end test_badge = "<a href='#{@config.results_base_url}/#{build_base_name compiler}.html'>![Test Badge](http://img.shields.io/badge/tests%20passed-#{test_string}-#{test_color}.png)</a>" build_failed = false if build_errors.positive? build_color = 'red' build_string = 'failing' build_failed = true elsif build_warnings.positive? build_color = 'yellow' build_string = 'warnings' else build_color = 'green' build_string = 'passing' end build_badge = "<a href='#{@config.results_base_url}/#{build_base_name compiler}.html'>![Build Badge](http://img.shields.io/badge/build%20status-#{build_string}-#{build_color}.png)</a>" cov_failed = false coverage_badge = '' if compiler[:coverage_enabled] coverage_percent = if @coverage_total_lines.zero? 0 else (@coverage_lines.to_f / @coverage_total_lines.to_f) * 100.0 end if coverage_percent >= compiler[:coverage_pass_limit] cov_color = 'green' elsif coverage_percent >= compiler[:coverage_warn_limit] cov_color = 'yellow' else cov_color = 'red' cov_failed = true end cov_str = "#{coverage_percent.round(2)}%25" coverage_badge = "<a href='#{@config.results_base_url}/#{build_base_name compiler}.html'>![Coverage Badge](http://img.shields.io/badge/coverage%20status-#{cov_str}-#{cov_color}.png)</a>" end github_status = if pending 'pending' elsif build_failed || test_failed || cov_failed || !@failure.nil? 'failure' else 'success' end = if pending 'Build Pending' elsif build_failed 'Build Failed' elsif test_failed "Tests Failed (#{test_results_passed} of #{test_results_total} tests passed, #{test_results_warning} test warnings)" elsif cov_failed 'Coverage Too Low' else "OK (#{test_results_passed} of #{test_results_total} tests passed, #{test_results_warning} test warnings)" end = Hash.new(0) @test_messages.each { |x| [x.] += 1 } $logger.debug("Message counts loaded: #{}") = '' .each do |, count| += if count > 1 " * #{count} tests had: #{}\n" else " * 1 test had: #{}\n" end end $logger.debug("Message counts string: #{}") test_failures_counts_str = '' test_results_failure_counts.sort { |a, b| a[0].casecmp(b[0]) }.each do |category, value| next if value.size <= 1 test_failures_counts_str += "\n#{category} Test Summary\n" sorted_values = value.sort do |a, b| if a[0] == 'Passed' -1 else b[0] == 'Passed' ? 1 : a[0].casecmp(b[0]) end end sorted_values.each do |failure, count| test_failures_counts_str += " * #{failure}: #{count}\n" end end github_document = if @failure.nil? <<-GIT #{@refspec} (#{@author}) - #{device_id compiler}: #{} #{ == '' ? '' : 'Messages:\n'} #{} #{test_failures_counts_str == '' ? '' : 'Failures:\n'} #{test_failures_counts_str} #{build_badge} #{test_badge} #{coverage_badge} GIT else <<-GIT <a href='#{@config.results_base_url}/#{build_base_name compiler}.html'>Unhandled Failure</a> GIT end if @test_run File.open("#{@dateprefix}-#{results_file_name compiler}", 'w+') { |f| f.write(json_document) } File.open("#{@dateprefix}-COMMENT-#{results_file_name compiler}", 'w+') { |f| f.write(github_document) } else begin if pending $logger.info('Posting pending results file') response = github_query(@client) do @client.create_contents( @config.results_repository, "#{@config.results_path}/#{this_branch_folder}/#{@dateprefix}-#{results_file_name compiler}", "#{Socket.gethostname}: Commit initial build results file: #{@dateprefix}-#{results_file_name compiler}", json_document ) end $logger.debug("Results document sha set: #{response.content.sha}") @results_document_sha = response.content.sha else raise 'Error, no prior results document sha set' if @results_document_sha.nil? $logger.info("Updating contents with sha #{@results_document_sha}") github_query(@client) do @client.update_contents( @config.results_repository, "#{@config.results_path}/#{this_branch_folder}/#{@dateprefix}-#{results_file_name compiler}", "#{Socket.gethostname}: Commit final build results file: #{@dateprefix}-#{results_file_name compiler}", @results_document_sha, json_document ) end end rescue => e $logger.error "Error creating / updating results contents file: #{e}" raise e end if !pending && @config.post_results_comment if !@commit_sha.nil? && @repository == @config.repository github_query(@client) { @client.create_commit_comment(@config.repository, @commit_sha, github_document) } elsif !@pull_id.nil? github_query(@client) { @client.add_comment(@config.repository, @pull_id, github_document) } end end if !@commit_sha.nil? && @config.post_results_status if @pull_request_base_repository.nil? github_query(@client) do @client.create_status( @config.repository, @commit_sha, github_status, :context => device_id(compiler), :target_url => "#{@config.results_base_url}/#{build_base_name compiler}.html", :description => ) end else github_query(@client) do @client.create_status( @pull_request_base_repository, @commit_sha, github_status, :context => device_id(compiler), :target_url => "#{@config.results_base_url}/#{build_base_name compiler}.html", :description => ) end end end end end |
#pull_request? ⇒ Boolean
105 106 107 |
# File 'lib/potentialbuild.rb', line 105 def pull_request? !@pull_id.nil? end |
#release? ⇒ Boolean
101 102 103 |
# File 'lib/potentialbuild.rb', line 101 def release? !@release_url.nil? end |
#results_file_name(compiler) ⇒ Object
124 125 126 |
# File 'lib/potentialbuild.rb', line 124 def results_file_name(compiler) "#{build_base_name compiler}-results.html" end |
#set_as_baseline ⇒ Object
89 90 91 |
# File 'lib/potentialbuild.rb', line 89 def set_as_baseline @acting_as_baseline = true end |
#short_build_base_name(compiler) ⇒ Object
128 129 130 |
# File 'lib/potentialbuild.rb', line 128 def short_build_base_name(compiler) "#{@config.repository_name}-#{compiler[:architecture]}-#{@config.os}-#{@buildid}" end |
#this_branch_folder ⇒ Object
255 256 257 258 259 260 261 |
# File 'lib/potentialbuild.rb', line 255 def this_branch_folder if !@tag_name.nil? && @tag_name != '' add_dashes(get_short_form(@tag_name)) else add_dashes(get_short_form(@branch_name)) end end |
#this_build_dir ⇒ Object
275 276 277 |
# File 'lib/potentialbuild.rb', line 275 def this_build_dir File.join(this_src_dir, 'build') end |
#this_regression_dir ⇒ Object
279 280 281 |
# File 'lib/potentialbuild.rb', line 279 def this_regression_dir File.join(Dir.pwd, 'clone_regressions') end |
#this_src_dir ⇒ Object
267 268 269 270 271 272 273 |
# File 'lib/potentialbuild.rb', line 267 def this_src_dir if @acting_as_baseline File.join(Dir.pwd, 'clone_baseline') else File.join(Dir.pwd, 'clone_branch') end end |
#try_to_repost_asset(response, asset_name) ⇒ Object
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 |
# File 'lib/potentialbuild.rb', line 539 def try_to_repost_asset(response, asset_name) asset_url = nil if !response.nil? && response.state == 'new' $logger.error("Error uploading asset #{response.url}") asset_url = response.url end if asset_url.nil? $logger.error('nil response, attempting to find release url') assets = github_query(@client) { @client.release_assets(@release_url) } assets.each do |a| if a.name == asset_name asset_url = a.url break end end end return if asset_url.nil? $logger.error("Found release url in list of assets: #{asset_url}") $logger.error("Deleting existing asset_url and trying again #{asset_url}") @package_results << CodeMessage.new('CMakeLists.txt', 1, 0, 'warning', "Error attempting to upload release asset, deleting and trying again. #{asset_url}\nDuring attempt #{try_num}") begin github_query(@client) { @client.delete_release_asset(asset_url) } rescue $logger.error("Error deleting failed asset, continuing to next try #{e}") @package_results << CodeMessage.new('CMakeLists.txt', 1, 0, 'warning', "Error attempting to delete failed release asset upload.\nDuring attempt #{try_num}\nRelease asset #{e}") end end |