show travis build failures for given build id/url, branch or current branch
July 18, 2015 ยท View on GitHub
#!/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