diff --git a/lib/travis/api/app/endpoint.rb b/lib/travis/api/app/endpoint.rb index f350eda5..c8a51d3e 100644 --- a/lib/travis/api/app/endpoint.rb +++ b/lib/travis/api/app/endpoint.rb @@ -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' } diff --git a/lib/travis/api/app/endpoint/accounts.rb b/lib/travis/api/app/endpoint/accounts.rb index f84ba216..21ca9c80 100644 --- a/lib/travis/api/app/endpoint/accounts.rb +++ b/lib/travis/api/app/endpoint/accounts.rb @@ -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 diff --git a/lib/travis/api/app/endpoint/artifacts.rb b/lib/travis/api/app/endpoint/artifacts.rb index 72cd4a25..b28082f2 100644 --- a/lib/travis/api/app/endpoint/artifacts.rb +++ b/lib/travis/api/app/endpoint/artifacts.rb @@ -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 diff --git a/lib/travis/api/app/endpoint/branches.rb b/lib/travis/api/app/endpoint/branches.rb index bf898790..b77e4ae2 100644 --- a/lib/travis/api/app/endpoint/branches.rb +++ b/lib/travis/api/app/endpoint/branches.rb @@ -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 diff --git a/lib/travis/api/app/endpoint/builds.rb b/lib/travis/api/app/endpoint/builds.rb index e7a5e957..c4b5021a 100644 --- a/lib/travis/api/app/endpoint/builds.rb +++ b/lib/travis/api/app/endpoint/builds.rb @@ -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 diff --git a/lib/travis/api/app/endpoint/hooks.rb b/lib/travis/api/app/endpoint/hooks.rb index 02154e56..2ac0dab7 100644 --- a/lib/travis/api/app/endpoint/hooks.rb +++ b/lib/travis/api/app/endpoint/hooks.rb @@ -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 diff --git a/lib/travis/api/app/endpoint/jobs.rb b/lib/travis/api/app/endpoint/jobs.rb index 893fefb4..4fde229d 100644 --- a/lib/travis/api/app/endpoint/jobs.rb +++ b/lib/travis/api/app/endpoint/jobs.rb @@ -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 diff --git a/lib/travis/api/app/endpoint/repositories.rb b/lib/travis/api/app/endpoint/repositories.rb index ade57472..2329e424 100644 --- a/lib/travis/api/app/endpoint/repositories.rb +++ b/lib/travis/api/app/endpoint/repositories.rb @@ -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 diff --git a/lib/travis/api/app/endpoint/result_image.rb b/lib/travis/api/app/endpoint/result_image.rb deleted file mode 100644 index ff2201a4..00000000 --- a/lib/travis/api/app/endpoint/result_image.rb +++ /dev/null @@ -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 diff --git a/lib/travis/api/app/endpoint/users.rb b/lib/travis/api/app/endpoint/users.rb index 3d2d90c2..8712e230 100644 --- a/lib/travis/api/app/endpoint/users.rb +++ b/lib/travis/api/app/endpoint/users.rb @@ -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 diff --git a/lib/travis/api/app/endpoint/workers.rb b/lib/travis/api/app/endpoint/workers.rb index 93d8796a..7a17a6e2 100644 --- a/lib/travis/api/app/endpoint/workers.rb +++ b/lib/travis/api/app/endpoint/workers.rb @@ -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 diff --git a/lib/travis/api/app/helpers/json_renderer.rb b/lib/travis/api/app/helpers/json_renderer.rb deleted file mode 100644 index 2d40a46b..00000000 --- a/lib/travis/api/app/helpers/json_renderer.rb +++ /dev/null @@ -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 diff --git a/lib/travis/api/app/helpers/mime_types.rb b/lib/travis/api/app/helpers/mime_types.rb new file mode 100644 index 00000000..9e002e62 --- /dev/null +++ b/lib/travis/api/app/helpers/mime_types.rb @@ -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 + diff --git a/lib/travis/api/app/helpers/respond_with.rb b/lib/travis/api/app/helpers/respond_with.rb new file mode 100644 index 00000000..48d3ec6f --- /dev/null +++ b/lib/travis/api/app/helpers/respond_with.rb @@ -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 diff --git a/lib/travis/api/app/helpers/responders/base.rb b/lib/travis/api/app/helpers/responders/base.rb new file mode 100644 index 00000000..fa639fb7 --- /dev/null +++ b/lib/travis/api/app/helpers/responders/base.rb @@ -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 diff --git a/lib/travis/api/app/helpers/responders/image.rb b/lib/travis/api/app/helpers/responders/image.rb new file mode 100644 index 00000000..a338ed71 --- /dev/null +++ b/lib/travis/api/app/helpers/responders/image.rb @@ -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 diff --git a/lib/travis/api/app/helpers/responders/json.rb b/lib/travis/api/app/helpers/responders/json.rb new file mode 100644 index 00000000..080914fa --- /dev/null +++ b/lib/travis/api/app/helpers/responders/json.rb @@ -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 diff --git a/lib/travis/api/app/helpers/responders/xml.rb b/lib/travis/api/app/helpers/responders/xml.rb new file mode 100644 index 00000000..39eca8c4 --- /dev/null +++ b/lib/travis/api/app/helpers/responders/xml.rb @@ -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__ + + + + diff --git a/lib/travis/api/app/helpers/result_image.rb b/lib/travis/api/app/helpers/result_image.rb deleted file mode 100644 index 3ddbef18..00000000 --- a/lib/travis/api/app/helpers/result_image.rb +++ /dev/null @@ -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 - diff --git a/lib/travis/api/app/responder.rb b/lib/travis/api/app/responder.rb index 8b8f0785..2c8f2f38 100644 --- a/lib/travis/api/app/responder.rb +++ b/lib/travis/api/app/responder.rb @@ -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 diff --git a/spec/integration/v1/builds_spec.rb b/spec/integration/v1/builds_spec.rb index 399e7926..cf1c6696 100644 --- a/spec/integration/v1/builds_spec.rb +++ b/spec/integration/v1/builds_spec.rb @@ -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 diff --git a/spec/unit/extensions/smart_constants_spec.rb b/spec/unit/extensions/smart_constants_spec.rb index 989913e1..5b8ada59 100644 --- a/spec/unit/extensions/smart_constants_spec.rb +++ b/spec/unit/extensions/smart_constants_spec.rb @@ -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 diff --git a/spec/unit/helpers/json_renderer_spec.rb b/spec/unit/helpers/json_renderer_spec.rb index 1a9ce80f..bbb7b606 100644 --- a/spec/unit/helpers/json_renderer_spec.rb +++ b/spec/unit/helpers/json_renderer_spec.rb @@ -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