refactor to responders, add the cc.xml stuff

This commit is contained in:
Sven Fuchs 2012-10-03 01:52:47 +02:00
parent 5a6f34005c
commit f6957636fb
23 changed files with 213 additions and 110 deletions

View File

@ -11,7 +11,9 @@ class Travis::Api::App
register :scoping
helpers :current_user
# TODO hmmm?
before { content_type :json }
error(ActiveRecord::RecordNotFound, Sinatra::NotFound) { not_found }
not_found { content_type =~ /json/ ? { 'file' => 'not found' } : 'file not found' }

View File

@ -4,7 +4,7 @@ class Travis::Api::App
class Endpoint
class Accounts < Endpoint
get '/', scope: :private do
body all(params).run, type: :accounts
respond_with all(params).run, type: :accounts
end
end
end

View File

@ -7,7 +7,7 @@ class Travis::Api::App
class Artifacts < Endpoint
# Fetches an artifact by it's *id*.
get '/:id' do |id|
body one(params).run
respond_with one(params).run
end
end
end

View File

@ -4,7 +4,7 @@ class Travis::Api::App
class Endpoint
class Branches < Endpoint
get '/' do
body all(params).run, type: :branches
respond_with all(params).run, type: :branches
end
end
end

View File

@ -4,11 +4,11 @@ class Travis::Api::App
class Endpoint
class Builds < Endpoint
get '/' do
body all(params).run
respond_with all(params).run
end
get '/:id' do
body one(params).run
respond_with one(params).run
end
end
end

View File

@ -4,7 +4,7 @@ class Travis::Api::App
class Endpoint
class Hooks < Endpoint
get '/', scope: :private do
body all(params).run, type: :hooks
respond_with all(params).run, type: :hooks
end
put '/:id?', scope: :private do

View File

@ -4,11 +4,11 @@ class Travis::Api::App
class Endpoint
class Jobs < Endpoint
get '/' do
body all(params).run
respond_with all(params).run
end
get '/:id' do
body one(params).run
respond_with one(params).run
end
end
end

View File

@ -4,12 +4,22 @@ class Travis::Api::App
class Endpoint
class Repositories < Endpoint
get '/' do
body all(params).run
respond_with all(params).run
end
get '/:id' do
body one(params).run
respond_with one(params).run
end
# TODO the format constraint neither seems to work nor fail?
get '/:id/cc.:format', format: 'xml' do
respond_with one(params).run
end
# get '/:owner_name/:name.:format', format: 'png' do
# pass unless params.key?('owner_name') && params.key?('name')
# result_image service(:repositories, :one, params).run(:raise => false)
# end
end
end
end

View File

@ -1,14 +0,0 @@
require 'travis/api/app'
class Travis::Api::App
class Endpoint
class ResultImage < Endpoint
# set(:prefix) { '/' }
# get '/:owner_name/:name.png' do
# pass unless params.key?('owner_name') && params.key?('name')
# result_image service(:repositories, :one, params).run(:raise => false)
# end
end
end
end

View File

@ -19,7 +19,7 @@ class Travis::Api::App
# }
# }
get '/:id?', scope: :private do
body current_user
respond_with current_user
end
put '/:id?', scope: :private do

View File

@ -4,7 +4,7 @@ class Travis::Api::App
class Endpoint
class Workers < Endpoint
get '/' do
body all(params).run
respond_with all(params).run
end
end
end

View File

@ -1,40 +0,0 @@
require 'travis/api/app'
class Travis::Api::App
module Helpers
# Allows routes to return either hashes or anything Travis::API.data can
# convert (in addition to the return values supported by Sinatra, of
# course). These values will be encoded in JSON.
module JsonRenderer
ACCEPT_VERSION = /vnd\.travis-ci\.(\d+)\+/
DEFAULT_VERSION = 'v1'
def respond_with(resource, options = {})
halt render_json(resource, options)
end
def body(value = nil, options = {}, &block)
value = render_json(value, options) if value
super(value, &block)
end
private
def render_json(resource, options = {})
options[:version] ||= api_version
options[:params] ||= params
builder = Travis::Api.builder(resource, options)
# builder || raise("could not determine a builder for #{resource}, #{options}")
resource = builder.new(resource, options[:params]).data.to_json if builder
resource = resource.to_json if resource.is_a? Hash
resource
end
def api_version
accept = request.env['HTTP_ACCEPT'] || ''
accept =~ ACCEPT_VERSION && "v#{$1}" || DEFAULT_VERSION
end
end
end
end

View File

@ -0,0 +1,24 @@
require 'travis/api/app'
class Travis::Api::App
module Helpers
module MimeTypes
def html?
request.accept =~ %r(text/html)
end
def json?
request.accept =~ %r(application/json)
end
def xml?
request.accept =~ %r(application/xml)
end
def png?
request.accept =~ %r(image/png)
end
end
end
end

View File

@ -0,0 +1,41 @@
require 'travis/api/app'
class Travis::Api::App
module Helpers
module Responders
autoload :Base, 'travis/api/app/helpers/responders/base'
autoload :Image, 'travis/api/app/helpers/responders/image'
autoload :Json, 'travis/api/app/helpers/responders/json'
autoload :Xml, 'travis/api/app/helpers/responders/xml'
end
# Allows routes to return either hashes or anything Travis::API.data can
# convert (in addition to the return values supported by Sinatra, of
# course). These values will be encoded in JSON.
module RespondWith
def respond_with(resource, options = {})
halt responder.new(request, headers, resource, options).render
end
def body(value = nil, options = {}, &block)
value = value.to_json if value.is_a?(Hash)
super(value, &block)
end
private
def responder
Responders.const_get(responder_type.to_s.camelize) # or raise shit
end
def responder_type
format_from_content_type || params[:format] || 'json'
end
# TODO is there no support for this kind of mime types?
def format_from_content_type
request.content_type && request.content_type.split(';').first.split('/').last
end
end
end
end

View File

@ -0,0 +1,12 @@
module Travis::Api::App::Helpers::Responders
class Base
attr_reader :request, :headers, :resource, :options
def initialize(request, headers, resource, options = {})
@request = request
@headers = headers
@resource = resource
@options = options
end
end
end

View File

@ -0,0 +1,24 @@
module Travis::Api::App::Helpers::Responders
class Image < Base
NAMES = { nil => 'unknown', 0 => 'passing', 1 => 'failing' }
def render
headers['Expires'] = Time.now.utc.httpdate
send_file filename(resource), type: :png, disposition: :inline
end
private
def filename(resource)
"#{root}/public/images/result/#{result(resource)}.png"
end
def result(resource)
NAMES[resource.try(:last_build_result_on, branch: params[:branch])]
end
def root
File.expand_path('.') # TODO wat.
end
end
end

View File

@ -0,0 +1,21 @@
module Travis::Api::App::Helpers::Responders
class Json < Base
ACCEPT_VERSION = /vnd\.travis-ci\.(\d+)\+/
DEFAULT_VERSION = 'v1'
def render
options[:version] ||= version
builder = Travis::Api.builder(resource, options) # || raise("could not determine a builder for #{resource}, #{options}")
resource = builder.new(self.resource, request.params).data if builder
resource = resource.to_json unless resource.is_a?(String)
resource
end
private
def version
request.accept.join =~ ACCEPT_VERSION && "v#{$1}" || DEFAULT_VERSION
end
end
end

View File

@ -0,0 +1,50 @@
module Travis::Api::App::Helpers::Responders
class Xml < Base
TEMPLATE = File.read(__FILE__).split("__END__").last.strip
STATUS = {
nil => 'Unknown',
0 => 'Success',
1 => 'Failure'
}
ACTIVITY = {
nil => 'Sleeping',
'started' => 'Building',
'finished' => 'Sleeping'
}
def render
TEMPLATE % data
end
private
def data
{
name: resource.slug,
url: [Travis.config.domain, resource.slug].join('/'),
activity: ACTIVITY[last_build.try(:state)],
label: last_build.try(:number),
status: STATUS[resource.last_build_result_on(request.params)],
time: last_build.finished_at.try(:strftime, '%Y-%m-%dT%H:%M:%S.%L%z')
}
end
def last_build
@last_build ||= resource.last_build
end
end
end
__END__
<Projects>
<Project
name="%{name}"
activity="%{activity}"
lastBuildStatus="%{status}"
lastBuildLabel="%{label}"
lastBuildTime="%{time}"
webUrl="%{url}" />
</Projects>

View File

@ -1,27 +0,0 @@
require 'travis/api/app'
require 'cgi'
module Travis::Api::App::Helpers
module ResultImage
RESULT_NAMES = { nil => 'unknown', 0 => 'passing', 1 => 'failing' }
def result_image(resource)
headers['Expires'] = CGI.rfc1123_date(Time.now.utc)
filename = filename(resource)
env['travis.sending-file'] = filename
send_file filename, type: :png, disposition: :inline
end
protected
def filename(resource)
root = File.expand_path("#{settings.root}/../../../../../") # TODO wat.
"#{root}/public/images/result/#{result(resource)}.png"
end
def result(resource)
RESULT_NAMES[resource.try(:last_build_result_on, branch: params[:branch])]
end
end
end

View File

@ -23,7 +23,7 @@ class Travis::Api::App
enable :raise_errors
# disable :dump_errors
register :subclass_tracker
helpers :json_renderer, :result_image
helpers :respond_with, :mime_types
end
configure :development do

View File

@ -9,7 +9,7 @@ describe 'Builds' do
it 'GET /builds?repository_id=1' do
response = get '/builds', { repository_id: repo.id }, headers
response.should deliver_json_for(repo.builds.was_started, version: 'v1')
response.should deliver_json_for(repo.builds.was_started.order('id DESC'), version: 'v1')
end
it 'GET /builds/1' do

View File

@ -7,8 +7,8 @@ describe Travis::Api::App::Extensions::SmartConstants do
describe :helpers do
it 'works' do # :)
some_app.helpers :json_renderer
some_app.ancestors.should include(Travis::Api::App::Helpers::JsonRenderer)
some_app.helpers :respond_with
some_app.ancestors.should include(Travis::Api::App::Helpers::RespondWith)
end
end

View File

@ -1,16 +1,16 @@
require 'spec_helper'
require 'json'
describe Travis::Api::App::Helpers::JsonRenderer do
before do
mock_app do
helpers Travis::Api::App::Helpers::JsonRenderer
get('/') { {'foo' => 'bar'} }
end
end
it 'renders body as json' do
get('/').should be_ok
JSON.load(body).should == {'foo' => 'bar'}
end
end
# describe Travis::Api::App::Helpers::JsonRenderer do
# before do
# mock_app do
# helpers Travis::Api::App::Helpers::JsonRenderer
# get('/') { {'foo' => 'bar'} }
# end
# end
#
# it 'renders body as json' do
# get('/').should be_ok
# JSON.load(body).should == {'foo' => 'bar'}
# end
# end