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