From c1466ce27b1e81b5d66039e0610b615bbc45d6fe Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Wed, 6 Nov 2013 14:15:28 -0500 Subject: [PATCH 01/12] Bump travis-core --- Gemfile.lock | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2d004666..acc224ef 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -23,7 +23,7 @@ GIT GIT remote: git://github.com/travis-ci/travis-core.git - revision: 9db978cabd740dddbc94d105cc4242b56afe2e9f + revision: 00580d7f38d65bc71bcb78eb93bfc53654d4394c specs: travis-core (0.0.1) actionmailer (~> 3.2.12) @@ -83,12 +83,12 @@ PATH GEM remote: https://rubygems.org/ specs: - actionmailer (3.2.14) - actionpack (= 3.2.14) + actionmailer (3.2.15) + actionpack (= 3.2.15) mail (~> 2.5.4) - actionpack (3.2.14) - activemodel (= 3.2.14) - activesupport (= 3.2.14) + actionpack (3.2.15) + activemodel (= 3.2.15) + activesupport (= 3.2.15) builder (~> 3.0.0) erubis (~> 2.7.0) journey (~> 1.0.4) @@ -96,15 +96,15 @@ GEM rack-cache (~> 1.2) rack-test (~> 0.6.1) sprockets (~> 2.2.1) - activemodel (3.2.14) - activesupport (= 3.2.14) + activemodel (3.2.15) + activesupport (= 3.2.15) builder (~> 3.0.0) - activerecord (3.2.14) - activemodel (= 3.2.14) - activesupport (= 3.2.14) + activerecord (3.2.15) + activemodel (= 3.2.15) + activesupport (= 3.2.15) arel (~> 3.0.2) tzinfo (~> 0.3.29) - activesupport (3.2.14) + activesupport (3.2.15) i18n (~> 0.6, >= 0.6.4) multi_json (~> 1.0) addressable (2.3.5) @@ -152,7 +152,7 @@ GEM hitimes (1.2.1) i18n (0.6.5) journey (1.0.4) - json (1.8.0) + json (1.8.1) kgio (2.8.0) listen (1.2.2) rb-fsevent (>= 0.9.3) @@ -197,9 +197,9 @@ GEM rack rack-test (0.6.2) rack (>= 1.0) - railties (3.2.14) - actionpack (= 3.2.14) - activesupport (= 3.2.14) + railties (3.2.15) + actionpack (= 3.2.15) + activesupport (= 3.2.15) rack-ssl (~> 1.3.2) rake (>= 0.8.7) rdoc (~> 3.4) From 3fa96de682404fc85a10c3802015876467b674bd Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Fri, 8 Nov 2013 23:55:21 -0500 Subject: [PATCH 02/12] WIP: Atom feed for /repos/:owner_name/:name/builds See travis-ci/travis-core#82 TODO: Link to indivisual build. TODO: Add specs. TODO: Review `#apply?` --- lib/travis/api/app/helpers/respond_with.rb | 2 +- lib/travis/api/app/responders.rb | 1 + lib/travis/api/app/responders/atom.rb | 63 ++++++++++++++++++++++ travis-api.gemspec | 4 +- 4 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 lib/travis/api/app/responders/atom.rb diff --git a/lib/travis/api/app/helpers/respond_with.rb b/lib/travis/api/app/helpers/respond_with.rb index 19f4c4fd..da21832d 100644 --- a/lib/travis/api/app/helpers/respond_with.rb +++ b/lib/travis/api/app/helpers/respond_with.rb @@ -49,7 +49,7 @@ class Travis::Api::App end def responders(resource, options) - [:Json, :Image, :Xml, :Plain].map do |name| + [:Atom, :Json, :Image, :Xml, :Plain].map do |name| Responders.const_get(name) end end diff --git a/lib/travis/api/app/responders.rb b/lib/travis/api/app/responders.rb index a81ac108..30c9ae54 100644 --- a/lib/travis/api/app/responders.rb +++ b/lib/travis/api/app/responders.rb @@ -2,6 +2,7 @@ require 'travis/api/app' class Travis::Api::App module Responders + autoload :Atom, 'travis/api/app/responders/atom' autoload :Base, 'travis/api/app/responders/base' autoload :Image, 'travis/api/app/responders/image' autoload :Json, 'travis/api/app/responders/json' diff --git a/lib/travis/api/app/responders/atom.rb b/lib/travis/api/app/responders/atom.rb new file mode 100644 index 00000000..a904197e --- /dev/null +++ b/lib/travis/api/app/responders/atom.rb @@ -0,0 +1,63 @@ +module Travis::Api::App::Responders + require 'securerandom' + + class Atom < Base + ATOM_FEED_ERB = ERB.new(File.read(__FILE__).split("__END__").last.strip) + + def apply? + if resource.is_a?(ActiveRecord::Relation) && resource.first.is_a?(Build) + @builds = resource + end + super && @builds + end + + def apply + super + + ATOM_FEED_ERB.result(binding) + end + + private + + def content_type + 'application/atom+xml;charset=utf-8' + end + + end +end + +__END__ + + + + + <%= @builds.first.repository.slug %> Builds + + urn:uuid:<%= SecureRandom.uuid %> + <%= DateTime.now.strftime %> + + <% @builds.each do |build| %> + + <%= build.repository.slug %> Build #<%= build.number %> + + urn:uuid:<%= SecureRandom.uuid %> + <%= build.finished_at || build.started_at %> + + <p> + <%= build.commit.message %> (<%= build.commit.committer_name %>) + <br/><br/> + State: <%= build.state %> + <br/> + Started at: <%= build.started_at ? build.started_at : 'not started' %> + <br/> + Finished at: <%= build.finished_at ? build.finished_at : + build.started_at ? 'still running' : 'not started' %> + </p> + + + <%= build.commit.committer_name %> + + + <% end %> + + \ No newline at end of file diff --git a/travis-api.gemspec b/travis-api.gemspec index b6596011..5f0d342c 100644 --- a/travis-api.gemspec +++ b/travis-api.gemspec @@ -22,7 +22,8 @@ Gem::Specification.new do |s| "Nick Schonning", "Patrick Williams", "James Dennes", - "Tim Carey-Smith" + "Tim Carey-Smith", + "Hiro Asari" ] s.email = [ @@ -135,6 +136,7 @@ Gem::Specification.new do |s| "lib/travis/api/app/middleware/rewrite.rb", "lib/travis/api/app/middleware/scope_check.rb", "lib/travis/api/app/responders.rb", + "lib/travis/api/app/responders/atom.rb", "lib/travis/api/app/responders/base.rb", "lib/travis/api/app/responders/image.rb", "lib/travis/api/app/responders/json.rb", From 148f2477e8e0dd41fcd753f9293efa97788cd1a1 Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Sat, 9 Nov 2013 07:07:10 -0500 Subject: [PATCH 03/12] Use here-doc for Atom feed template Rather than unnaturally re-reading __FILE__ and splitting, use a here-doc to clarify the intent. (Should also consider splitting it to a file.) --- lib/travis/api/app/responders/atom.rb | 74 +++++++++++++-------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/lib/travis/api/app/responders/atom.rb b/lib/travis/api/app/responders/atom.rb index a904197e..3cd4dba6 100644 --- a/lib/travis/api/app/responders/atom.rb +++ b/lib/travis/api/app/responders/atom.rb @@ -2,7 +2,43 @@ module Travis::Api::App::Responders require 'securerandom' class Atom < Base - ATOM_FEED_ERB = ERB.new(File.read(__FILE__).split("__END__").last.strip) + ATOM_FEED_ERB = ERB.new <<-EOF + + + + + <%= @builds.first.repository.slug %> Builds + + urn:uuid:<%= SecureRandom.uuid %> + Copyright (c) <%= DateTime.now.strftime("%Y") %> Travis CI GmbH + <%= DateTime.now.strftime %> + + <% @builds.each do |build| %> + + <%= build.repository.slug %> Build #<%= build.number %> + + urn:uuid:<%= SecureRandom.uuid %> + <%= build.finished_at || build.started_at %> + + <p> + <%= build.commit.message %> (<%= build.commit.committer_name %>) + <br/><br/> + State: <%= build.state %> + <br/> + Started at: <%= build.started_at ? build.started_at : 'not started' %> + <br/> + Finished at: <%= build.finished_at ? build.finished_at : + build.started_at ? 'still running' : 'not started' %> + </p> + + + <%= build.commit.committer_name %> + + + <% end %> + + + EOF def apply? if resource.is_a?(ActiveRecord::Relation) && resource.first.is_a?(Build) @@ -25,39 +61,3 @@ module Travis::Api::App::Responders end end - -__END__ - - - - - <%= @builds.first.repository.slug %> Builds - - urn:uuid:<%= SecureRandom.uuid %> - <%= DateTime.now.strftime %> - - <% @builds.each do |build| %> - - <%= build.repository.slug %> Build #<%= build.number %> - - urn:uuid:<%= SecureRandom.uuid %> - <%= build.finished_at || build.started_at %> - - <p> - <%= build.commit.message %> (<%= build.commit.committer_name %>) - <br/><br/> - State: <%= build.state %> - <br/> - Started at: <%= build.started_at ? build.started_at : 'not started' %> - <br/> - Finished at: <%= build.finished_at ? build.finished_at : - build.started_at ? 'still running' : 'not started' %> - </p> - - - <%= build.commit.committer_name %> - - - <% end %> - - \ No newline at end of file From 30b60283f8dc273bbaaca0f9f70faa61262dcbf6 Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Mon, 11 Nov 2013 09:39:13 -0500 Subject: [PATCH 04/12] Construct build result URL from parts Currently, there is no easy way to grab this information from the Build model. So we need to construct it from various parts at our disposal. --- lib/travis/api/app/responders/atom.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/travis/api/app/responders/atom.rb b/lib/travis/api/app/responders/atom.rb index 3cd4dba6..efa51afe 100644 --- a/lib/travis/api/app/responders/atom.rb +++ b/lib/travis/api/app/responders/atom.rb @@ -16,7 +16,7 @@ module Travis::Api::App::Responders <% @builds.each do |build| %> <%= build.repository.slug %> Build #<%= build.number %> - + " /> urn:uuid:<%= SecureRandom.uuid %> <%= build.finished_at || build.started_at %> From 26bdd84ae6d33be7211696d1606a320547cfa4a3 Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Mon, 11 Nov 2013 11:39:06 -0500 Subject: [PATCH 05/12] Eradicate @builds Unclear if ivar is beneficial here. --- lib/travis/api/app/responders/atom.rb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/travis/api/app/responders/atom.rb b/lib/travis/api/app/responders/atom.rb index efa51afe..4f88e751 100644 --- a/lib/travis/api/app/responders/atom.rb +++ b/lib/travis/api/app/responders/atom.rb @@ -7,13 +7,13 @@ module Travis::Api::App::Responders - <%= @builds.first.repository.slug %> Builds + <%= resource.first.repository.slug %> Builds urn:uuid:<%= SecureRandom.uuid %> Copyright (c) <%= DateTime.now.strftime("%Y") %> Travis CI GmbH <%= DateTime.now.strftime %> - <% @builds.each do |build| %> + <% resource.each do |build| %> <%= build.repository.slug %> Build #<%= build.number %> " /> @@ -41,10 +41,7 @@ module Travis::Api::App::Responders EOF def apply? - if resource.is_a?(ActiveRecord::Relation) && resource.first.is_a?(Build) - @builds = resource - end - super && @builds + super && resource.is_a?(ActiveRecord::Relation) && resource.first.is_a?(Build) end def apply From 8171d3915e7e47fc8f8b80cbce3c3225e4aaa8a4 Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Mon, 11 Nov 2013 11:40:37 -0500 Subject: [PATCH 06/12] Add integration specs for Atom feed These rudimentary specs do not test the correctness of the Atom feed format. --- spec/integration/v1/repositories_spec.rb | 8 ++++++++ spec/integration/v2/repositories_spec.rb | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/spec/integration/v1/repositories_spec.rb b/spec/integration/v1/repositories_spec.rb index 4f5795bf..c06e68bd 100644 --- a/spec/integration/v1/repositories_spec.rb +++ b/spec/integration/v1/repositories_spec.rb @@ -95,4 +95,12 @@ describe 'v1 repos' do get('/svenfuchs/minimal.png?branch=foo,bar').should deliver_result_image_for('passing') end end + + context 'with "Accept: application/atom+xml" header' do + let(:headers) { { 'HTTP_ACCEPT' => 'application/atom+xml' } } + it 'GET /repositories/svenfuchs/minimal/builds' do + response = get '/repositories/svenfuchs/minimal/builds', {}, headers + response.content_type.should =~ /^application\/atom\+xml/ + end + end end diff --git a/spec/integration/v2/repositories_spec.rb b/spec/integration/v2/repositories_spec.rb index 3d95ca0c..297cd1e8 100644 --- a/spec/integration/v2/repositories_spec.rb +++ b/spec/integration/v2/repositories_spec.rb @@ -139,4 +139,12 @@ describe 'Repos' do result.should deliver_result_image_for('passing') end end + + context 'with "Accept: application/atom+xml" header' do + let(:headers) { { 'HTTP_ACCEPT' => 'application/atom+xml' } } + it 'GET /repositories/svenfuchs/minimal/builds' do + response = get '/repositories/svenfuchs/minimal/builds', {}, headers + response.content_type.should =~ /^application\/atom\+xml/ + end + end end From e945476c8d4bdeb9a4610f9d7cdf82642e749b75 Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Mon, 11 Nov 2013 11:42:48 -0500 Subject: [PATCH 07/12] Prefer JSON to Atom feed We should not break the current behavior when the client sends `Accept: */*` HTTP header. --- lib/travis/api/app/helpers/respond_with.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/travis/api/app/helpers/respond_with.rb b/lib/travis/api/app/helpers/respond_with.rb index da21832d..611f789f 100644 --- a/lib/travis/api/app/helpers/respond_with.rb +++ b/lib/travis/api/app/helpers/respond_with.rb @@ -49,7 +49,7 @@ class Travis::Api::App end def responders(resource, options) - [:Atom, :Json, :Image, :Xml, :Plain].map do |name| + [:Json, :Atom, :Image, :Xml, :Plain].map do |name| Responders.const_get(name) end end From 53d2e950b91b0f4f8745cd4f9fc81de98dd37170 Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Mon, 11 Nov 2013 13:56:10 -0500 Subject: [PATCH 08/12] Set update element to RFC3339 format This is required by the RFC. http://tools.ietf.org/html/rfc4287#section-3.3 --- lib/travis/api/app/responders/atom.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/travis/api/app/responders/atom.rb b/lib/travis/api/app/responders/atom.rb index 4f88e751..747ff73d 100644 --- a/lib/travis/api/app/responders/atom.rb +++ b/lib/travis/api/app/responders/atom.rb @@ -1,5 +1,5 @@ module Travis::Api::App::Responders - require 'securerandom' + require 'date' class Atom < Base ATOM_FEED_ERB = ERB.new <<-EOF @@ -18,7 +18,7 @@ module Travis::Api::App::Responders <%= build.repository.slug %> Build #<%= build.number %> " /> urn:uuid:<%= SecureRandom.uuid %> - <%= build.finished_at || build.started_at %> + <%= ::DateTime.parse(build.updated_at.to_s).rfc3339 %> <p> <%= build.commit.message %> (<%= build.commit.committer_name %>) From ea3a5a7a0df9e447528ab980bd0a848ef6b0f856 Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Mon, 11 Nov 2013 14:11:35 -0500 Subject: [PATCH 09/12] Encode commit message So that HTML/XML tags in messages don't break the feed. --- lib/travis/api/app/responders/atom.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/travis/api/app/responders/atom.rb b/lib/travis/api/app/responders/atom.rb index 747ff73d..868a73aa 100644 --- a/lib/travis/api/app/responders/atom.rb +++ b/lib/travis/api/app/responders/atom.rb @@ -21,7 +21,7 @@ module Travis::Api::App::Responders <%= ::DateTime.parse(build.updated_at.to_s).rfc3339 %> <p> - <%= build.commit.message %> (<%= build.commit.committer_name %>) + <%= build.commit.message.encode(:xml => :text) %> (<%= build.commit.committer_name %>) <br/><br/> State: <%= build.state %> <br/> From 3b20120c724535a861674884e9a54de2cebec573 Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Mon, 11 Nov 2013 15:21:14 -0500 Subject: [PATCH 10/12] Accept `.atom` extension And return Atom feed for builds. Specs look different, because it needs to explicitly handle the common case where the client sends `Accept: */*`. --- lib/travis/api/app/helpers/mime_types.rb | 4 ++++ lib/travis/api/app/middleware/rewrite.rb | 6 +++++- spec/integration/v1/repositories_spec.rb | 10 +++++++++- spec/integration/v2/repositories_spec.rb | 8 ++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/travis/api/app/helpers/mime_types.rb b/lib/travis/api/app/helpers/mime_types.rb index 9e002e62..cf31b505 100644 --- a/lib/travis/api/app/helpers/mime_types.rb +++ b/lib/travis/api/app/helpers/mime_types.rb @@ -18,6 +18,10 @@ class Travis::Api::App def png? request.accept =~ %r(image/png) end + + def atom? + request.accept =~ %r(application/atom+xml) + end end end end diff --git a/lib/travis/api/app/middleware/rewrite.rb b/lib/travis/api/app/middleware/rewrite.rb index 8ac8b9f2..1f1a6f86 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|txt)$) + FORMAT = %r(\.(json|xml|png|txt|atom)$) V1_REPO_URL = %r(^(/[^/]+/[^/]+(?:/builds(?:/[\d]+)?|/cc)?)$) helpers :accept @@ -56,6 +56,10 @@ class Travis::Api::App env['travis.format'] == 'xml' end + def atom? + env['travis.format'] == 'atom' + end + def v1? accept_version == 'v1' end diff --git a/spec/integration/v1/repositories_spec.rb b/spec/integration/v1/repositories_spec.rb index c06e68bd..a7482a94 100644 --- a/spec/integration/v1/repositories_spec.rb +++ b/spec/integration/v1/repositories_spec.rb @@ -102,5 +102,13 @@ describe 'v1 repos' do response = get '/repositories/svenfuchs/minimal/builds', {}, headers response.content_type.should =~ /^application\/atom\+xml/ end - end + end + + context 'with .atom extension and "Accept: */*" header' do + let(:headers) { { 'HTTP_ACCEPT' => '*/*' } } + it 'GET /repositories/svenfuchs/minimal/builds.atom' do + response = get '/repositories/svenfuchs/minimal/builds.atom', {}, headers + response.content_type.should =~ /^application\/atom\+xml/ + end + end end diff --git a/spec/integration/v2/repositories_spec.rb b/spec/integration/v2/repositories_spec.rb index 297cd1e8..fcf89a1f 100644 --- a/spec/integration/v2/repositories_spec.rb +++ b/spec/integration/v2/repositories_spec.rb @@ -147,4 +147,12 @@ describe 'Repos' do response.content_type.should =~ /^application\/atom\+xml/ end end + + context 'with .atom extension' do + let(:headers) { { 'HTTP_ACCEPT' => '*/*' } } + it 'GET /repositories/svenfuchs/minimal/builds.atom' do + response = get '/repositories/svenfuchs/minimal/builds.atom', {}, headers + response.content_type.should =~ /^application\/atom\+xml/ + end + end end From 2645422fd3e2c0d0d76e6cccdffdf9d00f655e99 Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Mon, 11 Nov 2013 15:32:41 -0500 Subject: [PATCH 11/12] Atom feed's date should conform to RFC 3339. --- lib/travis/api/app/responders/atom.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/travis/api/app/responders/atom.rb b/lib/travis/api/app/responders/atom.rb index 868a73aa..726d296c 100644 --- a/lib/travis/api/app/responders/atom.rb +++ b/lib/travis/api/app/responders/atom.rb @@ -11,7 +11,7 @@ module Travis::Api::App::Responders urn:uuid:<%= SecureRandom.uuid %> Copyright (c) <%= DateTime.now.strftime("%Y") %> Travis CI GmbH - <%= DateTime.now.strftime %> + <%= DateTime.now.rfc3339 %> <% resource.each do |build| %> From fbf98f9cebac3d104bdca83bcaaa963ad5208381 Mon Sep 17 00:00:00 2001 From: Hiro Asari Date: Mon, 11 Nov 2013 15:43:47 -0500 Subject: [PATCH 12/12] Tweak feed and entry's IDs --- lib/travis/api/app/responders/atom.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/travis/api/app/responders/atom.rb b/lib/travis/api/app/responders/atom.rb index 726d296c..163cf7a3 100644 --- a/lib/travis/api/app/responders/atom.rb +++ b/lib/travis/api/app/responders/atom.rb @@ -9,7 +9,7 @@ module Travis::Api::App::Responders <%= resource.first.repository.slug %> Builds - urn:uuid:<%= SecureRandom.uuid %> + repo:<%= resource.first.repository.id %> Copyright (c) <%= DateTime.now.strftime("%Y") %> Travis CI GmbH <%= DateTime.now.rfc3339 %> @@ -17,7 +17,7 @@ module Travis::Api::App::Responders <%= build.repository.slug %> Build #<%= build.number %> " /> - urn:uuid:<%= SecureRandom.uuid %> + repo:<%= build.repository.id %>:build:<%= build.id %> <%= ::DateTime.parse(build.updated_at.to_s).rfc3339 %> <p>