diff --git a/lib/travis/api/app/helpers/respond_with.rb b/lib/travis/api/app/helpers/respond_with.rb index f7f8cbff..cfb1cc44 100644 --- a/lib/travis/api/app/helpers/respond_with.rb +++ b/lib/travis/api/app/helpers/respond_with.rb @@ -29,7 +29,7 @@ class Travis::Api::App end def responders(resource, options) - [:Service, :Json, :Image, :Xml].map do |name| + [:Service, :Json, :Image, :Xml, :Plain].map do |name| Responders.const_get(name) end end diff --git a/lib/travis/api/app/middleware/rewrite.rb b/lib/travis/api/app/middleware/rewrite.rb index 2a23b89a..3215602b 100644 --- a/lib/travis/api/app/middleware/rewrite.rb +++ b/lib/travis/api/app/middleware/rewrite.rb @@ -3,7 +3,7 @@ require 'travis/api/app' class Travis::Api::App class Middleware class Rewrite < Middleware - FORMAT = %r(\.(json|xml|png)$) + FORMAT = %r(\.(json|xml|png|txt)$) V1_REPO_URL = %r(^(/[^/]+/[^/]+(?:/builds(?:/[\d]+)?|/cc)?)$) helpers :accept diff --git a/lib/travis/api/app/responders.rb b/lib/travis/api/app/responders.rb index f8994685..a81ac108 100644 --- a/lib/travis/api/app/responders.rb +++ b/lib/travis/api/app/responders.rb @@ -5,6 +5,7 @@ class Travis::Api::App autoload :Base, 'travis/api/app/responders/base' autoload :Image, 'travis/api/app/responders/image' autoload :Json, 'travis/api/app/responders/json' + autoload :Plain, 'travis/api/app/responders/plain' autoload :Service, 'travis/api/app/responders/service' autoload :Xml, 'travis/api/app/responders/xml' end diff --git a/lib/travis/api/app/responders/plain.rb b/lib/travis/api/app/responders/plain.rb new file mode 100644 index 00000000..89328c96 --- /dev/null +++ b/lib/travis/api/app/responders/plain.rb @@ -0,0 +1,30 @@ +module Travis::Api::App::Responders + class Plain < Base + def apply? + # make sure that we don't leak anything by processing only Artifact::Log + # instances here. I don't want to create entire new API builder just + # for log's content for now. + # + # TODO: think how to handle other formats correctly + options[:format] == 'txt' && resource.is_a?(Artifact::Log) + end + + def apply + filename = resource.id + disposition = params[:attachment] ? 'attachment' : 'inline' + + headers['Content-Disposition'] = %(#{disposition}; filename="#{filename}") + + endpoint.content_type 'text/plain' + halt(params[:deansi] ? clear_ansi(resource.content) : resource.content) + end + + private + + def clear_ansi(content) + content.gsub(/\r\r/, "\r") + .gsub(/^.*\r(?!$)/, '') + .gsub(/\x1b(\[|\(|\))[;?0-9]*[0-9A-Za-z]/m, '') + end + end +end diff --git a/spec/unit/endpoint/artifacts_spec.rb b/spec/unit/endpoint/artifacts_spec.rb index e2b2c8d8..b701cff7 100644 --- a/spec/unit/endpoint/artifacts_spec.rb +++ b/spec/unit/endpoint/artifacts_spec.rb @@ -9,4 +9,36 @@ describe Travis::Api::App::Endpoint::Artifacts do get("/artifacts/#{id}", {}, 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json, */*; q=0.01').should be_ok end end + + describe 'GET /artifacts/:id.txt' do + it 'loads the artifact' do + response = get("/artifacts/#{id}.txt", {}) + + response.should be_ok + response.body.should == artifact.content + response.headers['Content-Disposition'].should == "inline; filename=\"#{artifact.id}\"" + end + + it 'sets Content-Disposition to attachment with attachment=true param' do + response = get("/artifacts/#{id}.txt", {'attachment' => true}) + + response.should be_ok + response.body.should == artifact.content + response.headers['Content-Disposition'].should == "attachment; filename=\"#{artifact.id}\"" + end + + describe 'with deansi param' do + let(:content) { + "Fetching (0%)\rFetching (10%)\rFetching (100%)\n\e[32m" + } + let(:artifact) { Factory(:log, :content => content) } + + it 'clears ansi escape control characters' do + response = get("/artifacts/#{id}.txt", {'deansi' => true}) + + response.should be_ok + response.body.should == "Fetching (100%)\n" + end + end + end end