diff --git a/.gitignore b/.gitignore index 28364b07..e5dba86d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ config/travis.yml .yardoc log/ +vendor diff --git a/.travis.yml b/.travis.yml index 157e917a..7341d32b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,15 @@ rvm: addons: postgresql: 9.3 before_script: + # create 'logs' table matching 'travis-logs' + - ./set_up_travis_logs.sh - 'RAILS_ENV=test bundle exec rake db:create db:structure:load --trace' + # replace 'logs' table in travis_test DB with that in travis_logs_test + - psql -c "DROP TABLE IF EXISTS logs CASCADE" -U postgres travis_test + - pg_dump -t logs travis_logs_test | psql -U postgres travis_test + notifications: irc: "irc.freenode.org#travis" services: - redis +cache: bundler diff --git a/Gemfile b/Gemfile index f8051f9c..89cee7dd 100644 --- a/Gemfile +++ b/Gemfile @@ -6,6 +6,7 @@ gemspec gem 'travis-core', github: 'travis-ci/travis-core' gem 'travis-support', github: 'travis-ci/travis-support' gem 'travis-sidekiqs', github: 'travis-ci/travis-sidekiqs', require: nil, ref: 'cde9741' +gem 'travis-yaml', github: 'travis-ci/travis-yaml' gem 'sinatra' gem 'sinatra-contrib', require: nil #github: 'sinatra/sinatra-contrib', require: nil diff --git a/Gemfile.lock b/Gemfile.lock index 0acf4838..21aff496 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -45,7 +45,7 @@ GIT GIT remote: git://github.com/travis-ci/travis-core.git - revision: 59e96ca2fef544365d79f7d240ad2b9c3fe9691e + revision: ef8fb67bd56569eb55d176f824bb62bc602c8f80 specs: travis-core (0.0.1) actionmailer (~> 3.2.12) @@ -80,6 +80,12 @@ GIT specs: travis-support (0.0.1) +GIT + remote: git://github.com/travis-ci/travis-yaml.git + revision: 7e6e31e82240e170ffc20dfd02c0353b3bd5d33b + specs: + travis-yaml (0.1.0) + GIT remote: https://gist.github.com/4269321.git revision: 8e2d21b924a69dd48191df6a18e51769f5a88614 @@ -204,7 +210,7 @@ GEM net-http-persistent (2.9.4) net-http-pipeline (1.0.1) pg (0.13.2) - polyglot (0.3.4) + polyglot (0.3.5) proxies (0.2.1) pry (0.9.12.4) coderay (~> 1.0) @@ -287,7 +293,7 @@ GEM eventmachine (>= 1.0.0) rack (>= 1.0.0) thor (0.14.6) - thread_safe (0.3.3) + thread_safe (0.3.4) tilt (1.4.1) timers (1.1.0) treetop (1.4.15) @@ -332,5 +338,6 @@ DEPENDENCIES travis-core! travis-sidekiqs! travis-support! + travis-yaml! unicorn yard-sinatra! diff --git a/README.md b/README.md index 5c82ce7c..d52ce9d1 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,48 @@ This is the app running on https://api.travis-ci.org/ +## Requirements + +1. PostgreSQL 9.3 or higher +1. Redis +1. RabbitMQ + ## Installation -Setup: +### Setup $ bundle install -Run tests: +### Database setup + +1. `rake db:create db:structure:load` +1. Clone `travis-logs` and copy the `logs` database (assume the PostgreSQL user is `postgres`): +```sh-session +cd .. +git clone https://github.com/travis-ci/travis-logs.git +cd travis-logs +rvm jruby do bundle exec rake db:migrate # `travis-logs` requires JRuby +psql -c "DROP TABLE IF EXISTS logs CASCADE" -U postgres travis_development +pg_dump -t logs travis_logs_development | psql -U postgres travis_development +``` + +Repeat the database steps for `RAILS_ENV=test`. +```sh-session +RAILS_ENV=test rake db:create db:structure:load +pushd ../travis-logs +RAILS_ENV=test rvm jruby do bundle exec rake db:migrate +psql -c "DROP TABLE IF EXISTS logs CASCADE" -U postgres travis_test +pg_dump -t logs travis_logs_test | psql -U postgres travis_test +popd +``` + + +### Run tests - $ RAILS_ENV=test rake db:create db:structure:load $ rake spec -Run the server: +### Run the server - $ rake db:create db:structure:load $ script/server ## Contributing diff --git a/config/nginx.conf.erb b/config/nginx.conf.erb index 2e0a0142..b901bab8 100644 --- a/config/nginx.conf.erb +++ b/config/nginx.conf.erb @@ -34,27 +34,6 @@ http { keepalive_timeout 5; location / { - add_header 'Access-Control-Allow-Origin' '*'; - add_header 'Access-Control-Allow-Credentials' 'true'; - add_header 'Access-Control-Expose-Headers' 'Content-Type, Cache-Control, Expires, Etag, Last-Modified'; - - if ($request_method = 'OPTIONS') { - add_header 'Access-Control-Allow-Origin' '*'; - add_header 'Access-Control-Allow-Credentials' 'true'; - add_header 'Access-Control-Expose-Headers' 'Content-Type, Cache-Control, Expires, Etag, Last-Modified'; - - # Tell browser to cache this pre-flight info for 20 days - add_header 'Access-Control-Max-Age' 1728000; - - add_header 'Access-Control-Allow-Methods' 'HEAD, GET, POST, PATCH, PUT, DELETE, OPTIONS'; - add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, Accept, If-None-Match, If-Modified-Since'; - - add_header 'Content-Length' 0; - add_header 'Content-Type' 'text/plain charset=UTF-8'; - - return 204; - } - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; diff --git a/lib/travis/api/app.rb b/lib/travis/api/app.rb index 391cece3..38982f7d 100644 --- a/lib/travis/api/app.rb +++ b/lib/travis/api/app.rb @@ -87,7 +87,7 @@ module Travis::Api [ 420, {}, ['Enhance Your Calm']] end - use Travis::Api::App::Cors if Travis.env == 'development' + use Travis::Api::App::Cors use Raven::Rack if Endpoint.production? use Rack::Protection::PathTraversal use Rack::SSL if Endpoint.production? diff --git a/lib/travis/api/app/endpoint/jobs.rb b/lib/travis/api/app/endpoint/jobs.rb index dec9ce34..0c497a58 100644 --- a/lib/travis/api/app/endpoint/jobs.rb +++ b/lib/travis/api/app/endpoint/jobs.rb @@ -64,6 +64,21 @@ class Travis::Api::App end end + patch '/:id/log', scope: :private do |id| + begin + self.service(:remove_log, params).run + rescue Travis::AuthorizationDenied => ade + status 401 + { error: { message: ade.message } } + rescue Travis::JobUnfinished, Travis::LogAlreadyRemoved => e + status 409 + { error: { message: e.message } } + rescue => e + status 500 + { error: { message: "Unexpected error occurred: #{e.message}" } } + end + end + get "/:job_id/annotations" do respond_with service(:find_annotations, params) end diff --git a/lib/travis/api/app/endpoint/lint.rb b/lib/travis/api/app/endpoint/lint.rb new file mode 100644 index 00000000..30437e51 --- /dev/null +++ b/lib/travis/api/app/endpoint/lint.rb @@ -0,0 +1,19 @@ +require 'travis/api/app' +require 'travis/yaml' + +class Travis::Api::App + class Endpoint + class Lint < Endpoint + def lint + request.body.rewind + content = params[:content] || request.body.read + parsed = Travis::Yaml.parse(content) + warnings = parsed.nested_warnings.map { |k, m| { key: k, message: m } } + { lint: { warnings: warnings } }.to_json + end + + post('/', scope: :public) { lint } + put('/', scope: :public) { lint } + end + end +end diff --git a/lib/travis/api/app/responders/image.rb b/lib/travis/api/app/responders/image.rb index 7eb540fc..df126d55 100644 --- a/lib/travis/api/app/responders/image.rb +++ b/lib/travis/api/app/responders/image.rb @@ -34,7 +34,7 @@ module Travis::Api::App::Responders end def root - File.expand_path('.') # TODO wat. + File.expand_path('.') end def last_modified diff --git a/lib/travis/api/app/responders/xml.rb b/lib/travis/api/app/responders/xml.rb index 410dec84..7db0a964 100644 --- a/lib/travis/api/app/responders/xml.rb +++ b/lib/travis/api/app/responders/xml.rb @@ -6,14 +6,15 @@ module Travis::Api::App::Responders class Xml < Base TEMPLATE_ERB = ERB.new <<-EOF -<% @resource.each do |r| %> +<% @resource.each do |repository| %> + <% next if build(repository).nil? %> + name="<%= repository.slug %>" + activity="<%= ACTIVITY[build(repository).state.to_sym] || ACTIVITY[:default] %>" + lastBuildStatus="<%= STATUS[build(repository).state.to_sym] || STATUS[:default] %>" + lastBuildLabel="<%= build(repository).try(:number) %>" + lastBuildTime="<%= build(repository).finished_at.try(:strftime, '%Y-%m-%dT%H:%M:%S.%L%z') %>" + webUrl="https://<%= Travis.config.client_domain %>/<%= repository.slug %>" /> <% end %> EOF @@ -23,7 +24,7 @@ module Travis::Api::App::Responders passed: 'Success', failed: 'Failure', errored: 'Error', - canceld: 'Canceled', + canceled: 'Canceled', } ACTIVITY = { @@ -42,6 +43,18 @@ module Travis::Api::App::Responders TEMPLATE_ERB.result(binding) end + def branch + params[:branch] + end + + def build(repository) + if branch.present? + repository.last_completed_build(branch) + else + repository.last_build + end + end + private def content_type diff --git a/set_up_travis_logs.sh b/set_up_travis_logs.sh new file mode 100755 index 00000000..54569ecb --- /dev/null +++ b/set_up_travis_logs.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +travis_retry() { + local result=0 + local count=1 + while [ $count -le 3 ]; do + [ $result -ne 0 ] && { + echo -e "\n${RED}The command \"$@\" failed. Retrying, $count of 3.${RESET}\n" >&2 + } + "$@" + result=$? + [ $result -eq 0 ] && break + count=$(($count + 1)) + sleep 1 + done + + [ $count -eq 3 ] && { + echo "\n${RED}The command \"$@\" failed 3 times.${RESET}\n" >&2 + } + + return $result +} + +# clone travis-logs +pushd $HOME +git clone --depth=1 https://github.com/travis-ci/travis-logs.git +cd travis-logs + +# install ruby runtime which travis-logs wants +RUBY_RUNTIME=$(cat .ruby-version) +rvm install $RUBY_RUNTIME +# using JRuby, migrate the 'logs' table in 'travis_test' database +BUNDLE_GEMFILE=$PWD/Gemfile +travis_retry rvm $RUBY_RUNTIME do bundle install +psql -c "CREATE DATABASE travis_logs_test;" -U postgres +cp $TRAVIS_BUILD_DIR/config/database.yml config/travis.yml +rvm $RUBY_RUNTIME do bundle exec rake db:migrate +popd diff --git a/spec/integration/v2/jobs_spec.rb b/spec/integration/v2/jobs_spec.rb index b865ed59..4a30c638 100644 --- a/spec/integration/v2/jobs_spec.rb +++ b/spec/integration/v2/jobs_spec.rb @@ -76,6 +76,58 @@ describe 'Jobs' do end end + describe 'PATCH /jobs/:job_id/log' do + let(:user) { User.where(login: 'svenfuchs').first } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: -1) } + + before :each do + headers.merge! 'HTTP_AUTHORIZATION' => "token #{token}" + end + + context 'when user does not have push permissions' do + before :each do + user.permissions.create!(repository_id: job.repository.id, :push => false) + end + + it 'returns status 401' do + response = patch "/jobs/#{job.id}/log", { reason: 'Because reason!' }, headers + response.status.should == 401 + end + end + + context 'when user has push permission' do + context 'when job is not finished' do + before :each do + job.stubs(:finished?).returns false + user.permissions.create!(repository_id: job.repository.id, :push => true) + end + + it 'returns status 409' do + response = patch "/jobs/#{job.id}/log", { reason: 'Because reason!' }, headers + response.status.should == 409 + end + end + + context 'when job is finished' do + let(:finished_job) { Factory(:test, state: 'passed') } + + before :each do + user.permissions.create!(repository_id: finished_job.repository.id, :push => true) + end + + it 'returns status 200' do + response = patch "/jobs/#{finished_job.id}/log", { reason: 'Because reason!' }, headers + response.status.should == 200 + end + + end + end + + context 'when job is not found' do + # TODO + end + end + it "GET /jobs/:id/annotations" do annotation_provider = Factory(:annotation_provider) annotation = annotation_provider.annotations.create(job_id: job.id, status: "passed", description: "Foobar") diff --git a/spec/unit/endpoint/lint_spec.rb b/spec/unit/endpoint/lint_spec.rb new file mode 100644 index 00000000..025130de --- /dev/null +++ b/spec/unit/endpoint/lint_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +describe Travis::Api::App::Endpoint::Lint do + let(:content) { "foo: bar" } + let(:body) { "{\"lint\":{\"warnings\":[{\"key\":[],\"message\":\"unexpected key \\\"foo\\\", dropping\"},{\"key\":[],\"message\":\"missing key \\\"language\\\", defaulting to \\\"ruby\\\"\"}]}}" } + + it "accepts content in parameter" do + response = post('/lint', content: content) + response.should be_ok + response.body.should be == body + end + + it "accepts content as body" do + response = put('/lint', content) + response.should be_ok + response.body.should be == body + end +end diff --git a/spec/unit/endpoint/logs_spec.rb b/spec/unit/endpoint/logs_spec.rb new file mode 100644 index 00000000..7f13049f --- /dev/null +++ b/spec/unit/endpoint/logs_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe Travis::Api::App::Endpoint::Logs do + let(:job) { Factory(:test) } + + describe "GET /logs/:id/" do + it "finds log successfully" do + get("/logs/#{job.log.id}", {}, "HTTP_ACCEPT" => "application/vnd.travis-ci.2+json, */*; q=0.01").should be_ok + end + end +end diff --git a/travis-api.gemspec b/travis-api.gemspec index 43570731..b3c53100 100644 --- a/travis-api.gemspec +++ b/travis-api.gemspec @@ -12,39 +12,47 @@ Gem::Specification.new do |s| "Piotr Sarnacki", "Konstantin Haase", "Sven Fuchs", - "Josh Kalderimis", "Mathias Meyer", - "Henrik Hodne", "Hiro Asari", + "Josh Kalderimis", + "Henrik Hodne", "Andre Arko", "Erik Michaels-Ober", - "Steve Richert", "Brian Ford", + "Steve Richert", + "rainsun", + "James Dennes", "Nick Schonning", "Patrick Williams", - "James Dennes", - "Tim Carey-Smith" + "Puneeth Chaganti", + "Thais Camilo and Konstantin Haase", + "Tim Carey-Smith", + "Zachary Scott" ] s.email = [ "drogus@gmail.com", "konstantin.mailinglists@googlemail.com", "me@svenfuchs.com", - "josh.kalderimis@gmail.com", "meyer@paperplanes.de", - "me@henrikhodne.com", "asari.ruby@gmail.com", - "konstantin.haase@gmail.com", + "josh.kalderimis@gmail.com", + "me@henrikhodne.com", "henrik@hodne.io", - "andre@arko.net", + "konstantin.haase@gmail.com", "svenfuchs@artweb-design.de", + "andre@arko.net", "sferik@gmail.com", - "steve.richert@gmail.com", "bford@engineyard.com", - "nschonni@gmail.com", + "steve.richert@gmail.com", + "rainsuner@gmail.com", "jdennes@gmail.com", + "nschonni@gmail.com", + "patrick@bittorrent.com", + "punchagan@muse-amuse.in", + "dev+narwen+rkh@rkh.im", "tim@spork.in", - "patrick@bittorrent.com" + "e@zzak.io" ] s.files = [ @@ -58,8 +66,6 @@ Gem::Specification.new do |s| "config/nginx.conf.erb", "config/puma-config.rb", "config/unicorn.rb", - "docs/00_overview.md", - "docs/01_cross_origin.md", "lib/tasks/build_update_branch.rake", "lib/tasks/build_update_pull_request_data.rake", "lib/tasks/encyrpt_all_data.rake", @@ -74,15 +80,15 @@ Gem::Specification.new do |s| "lib/travis/api/app/endpoint/broadcasts.rb", "lib/travis/api/app/endpoint/builds.rb", "lib/travis/api/app/endpoint/documentation.rb", - "lib/travis/api/app/endpoint/documentation/css/style.css", - "lib/travis/api/app/endpoint/documentation/resources.rb", "lib/travis/api/app/endpoint/endpoints.rb", "lib/travis/api/app/endpoint/home.rb", "lib/travis/api/app/endpoint/hooks.rb", "lib/travis/api/app/endpoint/jobs.rb", + "lib/travis/api/app/endpoint/lint.rb", "lib/travis/api/app/endpoint/logs.rb", "lib/travis/api/app/endpoint/repos.rb", "lib/travis/api/app/endpoint/requests.rb", + "lib/travis/api/app/endpoint/setting_endpoint.rb", "lib/travis/api/app/endpoint/uptime.rb", "lib/travis/api/app/endpoint/users.rb", "lib/travis/api/app/extensions.rb", @@ -104,24 +110,61 @@ Gem::Specification.new do |s| "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/badge.rb", "lib/travis/api/app/responders/base.rb", "lib/travis/api/app/responders/image.rb", "lib/travis/api/app/responders/json.rb", "lib/travis/api/app/responders/plain.rb", "lib/travis/api/app/responders/service.rb", "lib/travis/api/app/responders/xml.rb", + "lib/travis/api/app/skylight/dalli_probe.rb", + "lib/travis/api/app/skylight/redis_probe.rb", + "lib/travis/api/app/skylight/service_probe.rb", + "lib/travis/api/serializer.rb", + "lib/travis/api/v2.rb", + "lib/travis/api/v2/http.rb", + "lib/travis/api/v2/http/accounts.rb", + "lib/travis/api/v2/http/annotations.rb", + "lib/travis/api/v2/http/branch.rb", + "lib/travis/api/v2/http/branches.rb", + "lib/travis/api/v2/http/broadcasts.rb", + "lib/travis/api/v2/http/build.rb", + "lib/travis/api/v2/http/builds.rb", + "lib/travis/api/v2/http/caches.rb", + "lib/travis/api/v2/http/error.rb", + "lib/travis/api/v2/http/hooks.rb", + "lib/travis/api/v2/http/job.rb", + "lib/travis/api/v2/http/jobs.rb", + "lib/travis/api/v2/http/log.rb", + "lib/travis/api/v2/http/permissions.rb", + "lib/travis/api/v2/http/repositories.rb", + "lib/travis/api/v2/http/repository.rb", + "lib/travis/api/v2/http/request.rb", + "lib/travis/api/v2/http/requests.rb", + "lib/travis/api/v2/http/ssh_key.rb", + "lib/travis/api/v2/http/ssh_keys.rb", + "lib/travis/api/v2/http/ssl_key.rb", + "lib/travis/api/v2/http/user.rb", + "lib/travis/api/v2/http/validation_error.rb", "public/favicon.ico", "public/images/result/error.png", + "public/images/result/error.svg", "public/images/result/failing.png", + "public/images/result/failing.svg", "public/images/result/passing.png", + "public/images/result/passing.svg", "public/images/result/pending.png", + "public/images/result/pending.svg", "public/images/result/unknown.png", + "public/images/result/unknown.svg", "script/console", "script/server", + "set_up_travis_logs.sh", "spec/integration/formats_handling_spec.rb", "spec/integration/responders_spec.rb", "spec/integration/routes.backup.rb", "spec/integration/scopes_spec.rb", + "spec/integration/settings_endpoint_spec.rb", "spec/integration/uptime_spec.rb", "spec/integration/v1/branches_spec.rb", "spec/integration/v1/builds_spec.rb", @@ -134,12 +177,33 @@ Gem::Specification.new do |s| "spec/integration/v2/hooks_spec.rb", "spec/integration/v2/jobs_spec.rb", "spec/integration/v2/repositories_spec.rb", + "spec/integration/v2/requests_spec.rb", "spec/integration/v2/users_spec.rb", "spec/integration/v2_spec.backup.rb", "spec/integration/version_spec.rb", "spec/spec_helper.rb", + "spec/support/formats.rb", "spec/support/matchers.rb", "spec/unit/access_token_spec.rb", + "spec/unit/api/v2/http/accounts_spec.rb", + "spec/unit/api/v2/http/annotations_spec.rb", + "spec/unit/api/v2/http/branch_spec.rb", + "spec/unit/api/v2/http/branches_spec.rb", + "spec/unit/api/v2/http/broadcasts_spec.rb", + "spec/unit/api/v2/http/build_spec.rb", + "spec/unit/api/v2/http/builds_spec.rb", + "spec/unit/api/v2/http/caches_spec.rb", + "spec/unit/api/v2/http/hooks_spec.rb", + "spec/unit/api/v2/http/job_spec.rb", + "spec/unit/api/v2/http/jobs_spec.rb", + "spec/unit/api/v2/http/log_spec.rb", + "spec/unit/api/v2/http/permissions_spec.rb", + "spec/unit/api/v2/http/repositories_spec.rb", + "spec/unit/api/v2/http/repository_spec.rb", + "spec/unit/api/v2/http/request_spec.rb", + "spec/unit/api/v2/http/requests_spec.rb", + "spec/unit/api/v2/http/ssl_key_spec.rb", + "spec/unit/api/v2/http/user_spec.rb", "spec/unit/app_spec.rb", "spec/unit/cors_spec.rb", "spec/unit/default_spec.rb", @@ -148,10 +212,11 @@ Gem::Specification.new do |s| "spec/unit/endpoint/authorization_spec.rb", "spec/unit/endpoint/branches_spec.rb", "spec/unit/endpoint/builds_spec.rb", - "spec/unit/endpoint/documentation_spec.rb", "spec/unit/endpoint/endpoints_spec.rb", "spec/unit/endpoint/hooks_spec.rb", "spec/unit/endpoint/jobs_spec.rb", + "spec/unit/endpoint/lint_spec.rb", + "spec/unit/endpoint/logs_spec.rb", "spec/unit/endpoint/repos_spec.rb", "spec/unit/endpoint/users_spec.rb", "spec/unit/endpoint_spec.rb", @@ -165,6 +230,7 @@ Gem::Specification.new do |s| "spec/unit/middleware/scope_check_spec.rb", "spec/unit/responders/json_spec.rb", "spec/unit/responders/service_spec.rb", + "tmp/.gitkeep", "travis-api.gemspec" ]