|
#!/usr/bin/env ruby -rubygems -w |
|
# Lookup Travis CI build status of the current branch. |
|
# Exit with error status if build in progress or has failed. |
|
# |
|
# Dependenices: json (on ruby 1.8), hub |
|
|
|
begin |
|
require 'json' |
|
require 'time' |
|
require 'net/http' |
|
require 'hub/context' |
|
require 'hub/ssh_config' |
|
rescue LoadError |
|
abort $!.to_s |
|
end |
|
|
|
## helper methods |
|
|
|
include Hub::Context |
|
|
|
def get(url) |
|
case response = Net::HTTP.get_response(URI(url)) |
|
when Net::HTTPSuccess then JSON.parse(response.body) |
|
when Net::HTTPNotFound then abort "error: project not found on Travis" |
|
else abort "error: Travis API returned status #{response.code}" |
|
end |
|
end |
|
|
|
def to_branch(name) |
|
name = "refs/heads/#{name}" unless name.include?('/') |
|
Branch.new(local_repo, name) |
|
end |
|
|
|
## figure out current repo state |
|
|
|
branch = ARGV[0] ? to_branch(ARGV[0]) : current_branch or abort "no git branch" |
|
project = current_project or abort "git remote not pointing to a GitHub project" |
|
upstream = branch.upstream || to_branch("refs/remotes/#{project.remote}/#{branch.short_name}") |
|
pushed_rev = git_command("rev-parse #{upstream}") or abort "invalid upstream branch: #{upstream}" |
|
upstream_name = upstream.to_s.sub('refs/remotes/', '') |
|
|
|
## warn about unpushed commits |
|
|
|
if local_commits = git_command("rev-list --cherry #{upstream}...") |
|
warn "%d commits not yet pushed to %s" % [ |
|
local_commits.split("\n").size, |
|
upstream_name |
|
] |
|
end |
|
|
|
## talk to Travis |
|
|
|
builds = get('http://travis-ci.org/%s/builds.json' % current_project.name_with_owner) |
|
|
|
if build = builds.find {|b| b['commit'] == pushed_rev } |
|
if build['result'] |
|
if build['result'] == 0 |
|
puts "%s built OK." % upstream_name |
|
else |
|
warn "%s build failed." % upstream_name |
|
exit build['result'] |
|
end |
|
else |
|
started_at = Time.parse build['started_at'] |
|
seconds = Time.now - started_at |
|
abort "build in progress (%d seconds)" % seconds |
|
end |
|
else |
|
queue_name = case current_project.owner |
|
when 'rails', 'spree' then current_project.owner |
|
else |
|
conf = '.travis.yml' |
|
case lang = File.exist?(conf) && File.read(conf) =~ /\blanguage:\s*(\w+)\b/ && $1 |
|
when 'ruby' then 'common' |
|
when 'java', 'scala', 'groovy', 'clojure' then 'jvm' |
|
else |
|
lang || 'common' |
|
end |
|
end |
|
|
|
# check if build is waiting in the queue |
|
if queue = get("http://travis-ci.org/jobs.json?state=created&queue=builds.#{queue_name}") and !queue.empty? |
|
repo_id = builds.any? ? builds.first['repository_id'] : |
|
get('http://travis-ci.org/%s.json' % current_project.name_with_owner)['id'] |
|
|
|
if queue.any? { |b| b['repository_id'] == repo_id } |
|
abort "builds are waiting in the queue" |
|
end |
|
end |
|
|
|
abort "no build for #{upstream_name}" |
|
end |
The travis-client gem also provides a command line interface to Travis CI, but I like your interface much better. I'd be interested in taking inspiration from your gist, and making the gem's
travis
binary more script-friendly.Also, if you're interested, I've written a blog post about displaying a project's Travis CI status in your shell prompt.