Last active
August 29, 2015 14:21
-
-
Save grosser/df68f5461d45601f37f0 to your computer and use it in GitHub Desktop.
Analyze travis failures from forking_test_runner across all jobs in the build
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# | |
# show travis build failures for given build id/url, branch or current branch | |
# streams logs and shows errors as they happen | |
# | |
def usage | |
puts <<-TEXT.gsub(/^ /, "") | |
Setup | |
----- | |
gem install travis ruby-progressbar | |
travis login --pro | |
# create a new token at https://github.com/settings/tokens/new with repo access | |
git config github.token NEW_TOKEN --local | |
Usage | |
----- | |
#{$0} # show latest build on current branch | |
#{$0} <build-id or build-url> # show build | |
#{$0} branch-name # show build on this branch | |
TEXT | |
exit 1 | |
end | |
raise "cannot be used with bundle exec" if defined?(Bundler) | |
begin | |
gem "travis" | |
require "travis" | |
gem "ruby-progressbar" | |
require "ruby-progressbar" | |
rescue LoadError | |
usage | |
end | |
def built_branches | |
YAML.load_file('.travis.yml').fetch('branches').fetch('only') | |
end | |
def find_build_for_branch(slug, branch) | |
if built_branches.include?(branch) | |
Travis::Pro::Repository.find(slug).last_on_branch(branch) | |
else | |
find_build_via_pr(slug, branch) | |
end | |
end | |
def find_build_via_pr(slug, branch) | |
# fetch PR number for current branch from github | |
github_token = `git config github.token`.strip | |
usage if github_token.empty? | |
github_url = "https://api.github.com/repos/#{slug}/pulls?state=open&head=#{slug.split("/").first}:#{branch}" | |
github_response = `curl --silent -H "Authorization: token #{github_token}" '#{github_url}'` | |
pr_number = github_response[/"number": (\d+),/, 1] || raise("Could not find PR number") | |
# find the build with that PR and show some progress | |
puts "Looking for PR #{pr_number}" | |
Travis::Pro::Repository.find(slug).each_build do |b| | |
if b.pull_request_number == pr_number.to_i | |
print "\n" | |
return b | |
else | |
print "." | |
end | |
end | |
raise "Could not find a build for PR" | |
end | |
# use static estimate since real estimate is inaccurate | |
# - startup is very slow so estimate is too big | |
# - when starting mid-build estimate is too low | |
ProgressBar::Components::Time.class_eval do | |
def estimated_seconds_remaining | |
remaining = (ESTIMATED_BUILD_TIME / progress.total) * (progress.total - progress.progress) | |
remaining.round | |
end | |
end | |
ESTIMATED_BUILD_TIME = 15*60.0 | |
slug = "my_org/my_repo" | |
base_url = "https://something.travis-ci.com/#{slug}" | |
travis_config = File.expand_path("~/.travis/config.yml") | |
usage unless File.exist?(travis_config) | |
Travis::Pro.access_token = YAML.load_file(travis_config).fetch("endpoints").fetch(Travis::Client::PRO_URI).fetch("access_token") | |
current_branch = `git rev-parse --abbrev-ref HEAD`.strip | |
build = if ARGV[0] =~ /\A(\d+)\z|\Ahttp.*\/(\d+)\Z/ # id or full url | |
Travis::Pro::Build.find($1 || $2) | |
elsif ARGV[0] =~ /\A[a-z\d_\/-]+\z/ # branch name | |
find_build_for_branch(slug, ARGV[0]) | |
else | |
find_build_for_branch(slug, current_branch) | |
end | |
puts "Analyzing #{current_branch} build #{base_url}/builds/#{build.id}" | |
progressbar = ProgressBar.create(title: "Tests", total: Dir["test/**/*_test.rb"].size, format: '%t %p%% (%c/%C) |%e | %a | %B') | |
failed_tests = [] | |
build.jobs.map do |job| | |
Thread.new do | |
reported = [] | |
collected = "" | |
begin | |
job.log.body do |chunk| | |
collected << chunk | |
failed = collected.scan(/^------ <<< (\S+) ---- Failed/m).map(&:first) | |
finished = collected.scan(/^------ >>> (\S+)/).map(&:first) | |
failed -= reported | |
finished -= reported | |
reported += finished | |
Thread.exclusive do | |
failed.each do |failure| | |
failed_tests << failure | |
puts collected[/^------ >>> #{failure}.*?------ <<< #{failure} ---- Failed/m] | |
end | |
finished.each { progressbar.increment unless progressbar.finished? } | |
end | |
end | |
rescue Travis::Client::SSLError, Errno::ECONNRESET | |
# SSL error fetching log for job for whatever reason some of the logs cannot be fetched ... | |
rescue NoMethodError | |
# pusher blows up with NoMethodError on every stream end when streaming (job was live and then finishes) | |
# https://github.com/travis-ci/travis.rb/issues/198 | |
end | |
end | |
end.each(&:join) | |
progressbar.finish | |
failed_jobs = build.jobs.reject(&:passed?) | |
if failed_jobs.any? | |
puts "\nFailed jobs:" | |
failed_jobs.each do |job| | |
puts "#{base_url}/jobs/#{job.id}" | |
end | |
if failed_tests.any? | |
puts "\nFailed tests:" | |
puts failed_tests | |
end | |
exit 1 | |
else | |
puts "SUCCESS!" | |
exit 0 | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment