Merge branch 'master' into rkh-mustermann

Conflicts:
	Gemfile.lock
This commit is contained in:
Konstantin Haase 2014-12-01 12:43:11 +01:00
commit 162c615919
55 changed files with 784 additions and 229 deletions

View File

@ -1,3 +1,2 @@
https://github.com/heroku/heroku-buildpack-ruby.git https://github.com/heroku/heroku-buildpack-ruby.git
https://github.com/drogus/last-commit-sha-buildpack.git https://github.com/drogus/last-commit-sha-buildpack.git
https://github.com/ryandotsmith/nginx-buildpack.git

1
.ruby-version Normal file
View File

@ -0,0 +1 @@
2.1.4

View File

@ -1,19 +1,17 @@
language: ruby language: ruby
sudo: false
rvm:
- 2.1.4
env: env:
global: global:
- RUBY_GC_MALLOC_LIMIT=90000000 - RUBY_GC_MALLOC_LIMIT=90000000
- RUBY_FREE_MIN=200000 - RUBY_GC_HEAP_FREE_SLOTS=200000
rvm: cache: bundler
- 2.1.2
addons: addons:
postgresql: 9.3 postgresql: 9.3
before_script:
# create 'logs' table matching 'travis-logs'
- 'RAILS_ENV=test bundle exec rake db:create db:structure:load mv_migrations db:migrate --trace'
notifications:
irc: "irc.freenode.org#travis"
services: services:
- redis - redis
cache: bundler before_script:
sudo: false - 'RAILS_ENV=test bundle exec rake db:create db:migrate --trace'
notifications:
irc: "irc.freenode.org#travis"

View File

@ -1,10 +1,9 @@
ruby '2.1.2'
source 'https://rubygems.org' source 'https://rubygems.org'
gemspec gemspec
gem 'travis-core', github: 'travis-ci/travis-core' gem 'travis-core', github: 'travis-ci/travis-core'
gem 'travis-support', github: 'travis-ci/travis-support' gem 'travis-support', github: 'travis-ci/travis-support'
gem 'travis-config', '~> 0.1.0'
gem 'travis-sidekiqs', github: 'travis-ci/travis-sidekiqs', require: nil, ref: 'cde9741' gem 'travis-sidekiqs', github: 'travis-ci/travis-sidekiqs', require: nil, ref: 'cde9741'
gem 'travis-yaml', github: 'travis-ci/travis-yaml' gem 'travis-yaml', github: 'travis-ci/travis-yaml'
gem 'sinatra' gem 'sinatra'
@ -23,6 +22,7 @@ gem 'dalli'
gem 'pry' gem 'pry'
gem 'metriks', '0.9.9.6' gem 'metriks', '0.9.9.6'
gem 'metriks-librato_metrics', github: 'eric/metriks-librato_metrics' gem 'metriks-librato_metrics', github: 'eric/metriks-librato_metrics'
gem 'micro_migrations'
group :test do group :test do
gem 'rspec', '~> 2.13' gem 'rspec', '~> 2.13'
@ -39,5 +39,4 @@ end
group :development, :test do group :development, :test do
gem 'rake', '~> 0.9.2' gem 'rake', '~> 0.9.2'
gem 'micro_migrations', git: 'https://gist.github.com/4269321.git'
end end

View File

@ -7,16 +7,15 @@ GIT
GIT GIT
remote: git://github.com/getsentry/raven-ruby.git remote: git://github.com/getsentry/raven-ruby.git
revision: 8e63d48823a60b7d591932582b6e3ee3678fea60 revision: 84392e5db701f0b5c66802aab9cc82ef9a5ad830
specs: specs:
sentry-raven (0.9.3) sentry-raven (0.10.1)
faraday (>= 0.7.6) faraday (>= 0.7.6)
hashie (>= 1.1.0)
uuidtools uuidtools
GIT GIT
remote: git://github.com/rack/rack-contrib.git remote: git://github.com/rack/rack-contrib.git
revision: 5c12ace4ba2b9e4802e4d948a8ee0114da18760b revision: 1b11346d729efd88b274cd7f704e0bca9eb3de7a
specs: specs:
rack-contrib (1.2.0) rack-contrib (1.2.0)
rack (>= 0.9.1) rack (>= 0.9.1)
@ -37,7 +36,7 @@ GIT
GIT GIT
remote: git://github.com/travis-ci/travis-core.git remote: git://github.com/travis-ci/travis-core.git
revision: beaa1c74ff078f2820c65a3d6c4a2aa0bd6c9c0b revision: a5277a1f47a8615672607026239af49a217e2830
specs: specs:
travis-core (0.0.1) travis-core (0.0.1)
actionmailer (~> 3.2.19) actionmailer (~> 3.2.19)
@ -48,7 +47,7 @@ GIT
hashr (~> 0.0.19) hashr (~> 0.0.19)
metriks (~> 0.9.7) metriks (~> 0.9.7)
multi_json multi_json
pusher (~> 0.11.0) pusher (~> 0.12.0)
railties (~> 3.2.19) railties (~> 3.2.19)
rake rake
redis (~> 3.0) redis (~> 3.0)
@ -56,6 +55,7 @@ GIT
s3 (~> 0.3) s3 (~> 0.3)
simple_states (~> 1.0.0) simple_states (~> 1.0.0)
thor (~> 0.14.6) thor (~> 0.14.6)
travis-config (~> 0.1.0)
virtus (~> 1.0.0) virtus (~> 1.0.0)
GIT GIT
@ -68,22 +68,16 @@ GIT
GIT GIT
remote: git://github.com/travis-ci/travis-support.git remote: git://github.com/travis-ci/travis-support.git
revision: 930b1320b20271b6a08f44870ac55ba8d3ca2c1b revision: 40365216662f639d36fc3a0463c4e189ee1563dd
specs: specs:
travis-support (0.0.1) travis-support (0.0.1)
GIT GIT
remote: git://github.com/travis-ci/travis-yaml.git remote: git://github.com/travis-ci/travis-yaml.git
revision: 8b02f2753ac488e6f5ea071cf9a96cce097c4e58 revision: 08ec0c4d0cf3366cd971d4acd9aadbc0db68f85d
specs: specs:
travis-yaml (0.1.0) travis-yaml (0.1.0)
GIT
remote: https://gist.github.com/4269321.git
revision: 8e2d21b924a69dd48191df6a18e51769f5a88614
specs:
micro_migrations (0.0.1)
PATH PATH
remote: . remote: .
specs: specs:
@ -100,11 +94,11 @@ PATH
thin (~> 1.4) thin (~> 1.4)
travis-core travis-core
travis-support travis-support
useragent
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
CFPropertyList (2.2.8)
actionmailer (3.2.19) actionmailer (3.2.19)
actionpack (= 3.2.19) actionpack (= 3.2.19)
mail (~> 2.5.4) mail (~> 2.5.4)
@ -118,8 +112,8 @@ GEM
rack-cache (~> 1.2) rack-cache (~> 1.2)
rack-test (~> 0.6.1) rack-test (~> 0.6.1)
sprockets (~> 2.2.1) sprockets (~> 2.2.1)
active_model_serializers (0.8.1) active_model_serializers (0.9.0)
activemodel (>= 3.0) activemodel (>= 3.2)
activemodel (3.2.19) activemodel (3.2.19)
activesupport (= 3.2.19) activesupport (= 3.2.19)
builder (~> 3.0.0) builder (~> 3.0.0)
@ -142,13 +136,25 @@ GEM
backports (2.8.2) backports (2.8.2)
builder (3.0.4) builder (3.0.4)
bunny (0.8.0) bunny (0.8.0)
celluloid (0.12.4) celluloid (0.12.0)
facter (>= 1.6.12)
timers (>= 1.0.0) timers (>= 1.0.0)
chunky_png (1.3.3)
coder (0.4.0) coder (0.4.0)
coderay (1.1.0) coderay (1.1.0)
coercible (1.0.0) coercible (1.0.0)
descendants_tracker (~> 0.0.1) descendants_tracker (~> 0.0.1)
compass (1.0.1)
chunky_png (~> 1.2)
compass-core (~> 1.0.1)
compass-import-once (~> 1.0.5)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
sass (>= 3.3.13, < 3.5)
compass-core (1.0.1)
multi_json (~> 1.0)
sass (>= 3.3.0, < 3.5)
compass-import-once (1.0.5)
sass (>= 3.2, < 3.5)
connection_pool (0.9.3) connection_pool (0.9.3)
daemons (1.1.9) daemons (1.1.9)
dalli (2.7.2) dalli (2.7.2)
@ -163,13 +169,11 @@ GEM
equalizer (0.0.9) equalizer (0.0.9)
erubis (2.7.0) erubis (2.7.0)
eventmachine (1.0.3) eventmachine (1.0.3)
facter (2.1.0)
CFPropertyList (~> 2.2.6)
factory_girl (2.4.2) factory_girl (2.4.2)
activesupport activesupport
faraday (0.9.0) faraday (0.9.0)
multipart-post (>= 1.2, < 3) multipart-post (>= 1.2, < 3)
ffi (1.9.3) ffi (1.9.6)
foreman (0.64.0) foreman (0.64.0)
dotenv (~> 0.7.0) dotenv (~> 0.7.0)
thor (>= 0.13.6) thor (>= 0.13.6)
@ -180,10 +184,10 @@ GEM
multi_json (~> 1.0) multi_json (~> 1.0)
net-http-persistent (>= 2.7) net-http-persistent (>= 2.7)
net-http-pipeline net-http-pipeline
hashie (3.1.0)
hashr (0.0.22) hashr (0.0.22)
hike (1.2.3) hike (1.2.3)
hitimes (1.2.2) hitimes (1.2.2)
httpclient (2.3.4.1)
i18n (0.6.11) i18n (0.6.11)
ice_nine (0.11.0) ice_nine (0.11.0)
journey (1.0.4) journey (1.0.4)
@ -203,27 +207,31 @@ GEM
atomic (~> 1.0) atomic (~> 1.0)
avl_tree (~> 1.1.2) avl_tree (~> 1.1.2)
hitimes (~> 1.1) hitimes (~> 1.1)
micro_migrations (0.0.2)
activerecord
railties
mime-types (1.25.1) mime-types (1.25.1)
mocha (0.14.0) mocha (0.14.0)
metaclass (~> 0.0.1) metaclass (~> 0.0.1)
multi_json (1.10.1) multi_json (1.10.1)
multipart-post (2.0.0) multipart-post (2.0.0)
mustermann (0.3.0) mustermann (0.4.0)
tool (~> 0.2) tool (~> 0.2)
net-http-persistent (2.9.4) net-http-persistent (2.9.4)
net-http-pipeline (1.0.1) net-http-pipeline (1.0.1)
pg (0.13.2) pg (0.13.2)
polyglot (0.3.5) polyglot (0.3.5)
proxies (0.2.1) proxies (0.2.1)
pry (0.10.0) pry (0.10.1)
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.8.1) method_source (~> 0.8.1)
slop (~> 3.4) slop (~> 3.4)
pusher (0.11.3) pusher (0.12.0)
httpclient (~> 2.3.0)
multi_json (~> 1.0) multi_json (~> 1.0)
signature (~> 0.1.6) signature (~> 0.1.6)
rack (1.4.5) rack (1.4.5)
rack-attack (4.1.0) rack-attack (4.2.0)
rack rack
rack-protection (1.5.3) rack-protection (1.5.3)
rack rack
@ -249,7 +257,7 @@ GEM
json (~> 1.4) json (~> 1.4)
redcarpet (2.3.0) redcarpet (2.3.0)
redis (3.1.0) redis (3.1.0)
redis-namespace (1.5.0) redis-namespace (1.5.1)
redis (~> 3.0, >= 3.0.4) redis (~> 3.0, >= 3.0.4)
rerun (0.8.2) rerun (0.8.2)
listen (~> 1.0.3) listen (~> 1.0.3)
@ -258,18 +266,22 @@ GEM
rspec-core (~> 2.99.0) rspec-core (~> 2.99.0)
rspec-expectations (~> 2.99.0) rspec-expectations (~> 2.99.0)
rspec-mocks (~> 2.99.0) rspec-mocks (~> 2.99.0)
rspec-core (2.99.1) rspec-core (2.99.2)
rspec-expectations (2.99.1) rspec-expectations (2.99.2)
diff-lcs (>= 1.1.3, < 2.0) diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.99.1) rspec-mocks (2.99.2)
s3 (0.3.21) s3 (0.3.21)
proxies (~> 0.2.0) proxies (~> 0.2.0)
sidekiq (2.5.4) sass (3.4.6)
sidekiq (2.5.0)
celluloid (~> 0.12.0) celluloid (~> 0.12.0)
compass
connection_pool (~> 0.9.2) connection_pool (~> 0.9.2)
multi_json (~> 1) multi_json (~> 1)
redis (~> 3) redis (~> 3)
redis-namespace redis-namespace
sass
sprockets-sass
signature (0.1.7) signature (0.1.7)
simple_states (1.0.1) simple_states (1.0.1)
activesupport activesupport
@ -285,37 +297,43 @@ GEM
rack-test rack-test
sinatra (~> 1.4.0) sinatra (~> 1.4.0)
tilt (~> 1.3) tilt (~> 1.3)
slop (3.5.0) slop (3.6.0)
sprockets (2.2.2) sprockets (2.2.2)
hike (~> 1.2) hike (~> 1.2)
multi_json (~> 1.0) multi_json (~> 1.0)
rack (~> 1.0) rack (~> 1.0)
tilt (~> 1.1, != 1.3.0) tilt (~> 1.1, != 1.3.0)
thin (1.6.2) sprockets-sass (1.2.0)
daemons (>= 1.0.9) sprockets (~> 2.0)
eventmachine (>= 1.0.0) tilt (~> 1.1)
rack (>= 1.0.0) thin (1.6.3)
daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0)
rack (~> 1.0)
thor (0.14.6) thor (0.14.6)
thread_safe (0.3.4) thread_safe (0.3.4)
tilt (1.4.1) tilt (1.4.1)
timers (3.0.1) timers (4.0.1)
hitimes hitimes
tool (0.2.2) tool (0.2.3)
travis-config (0.1.0)
hashr (~> 0.0)
treetop (1.4.15) treetop (1.4.15)
polyglot polyglot
polyglot (>= 0.3.1) polyglot (>= 0.3.1)
tzinfo (0.3.40) tzinfo (0.3.42)
unicorn (4.8.3) unicorn (4.8.3)
kgio (~> 2.6) kgio (~> 2.6)
rack rack
raindrops (~> 0.7) raindrops (~> 0.7)
uuidtools (2.1.4) useragent (0.10.0)
uuidtools (2.1.5)
virtus (1.0.3) virtus (1.0.3)
axiom-types (~> 0.1) axiom-types (~> 0.1)
coercible (~> 1.0) coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3) descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9) equalizer (~> 0.0, >= 0.0.9)
yard (0.8.7.4) yard (0.8.7.6)
PLATFORMS PLATFORMS
ruby ruby
@ -330,7 +348,7 @@ DEPENDENCIES
gh gh
metriks (= 0.9.9.6) metriks (= 0.9.9.6)
metriks-librato_metrics! metriks-librato_metrics!
micro_migrations! micro_migrations
mocha (~> 0.12) mocha (~> 0.12)
pry pry
rack-attack rack-attack
@ -344,6 +362,7 @@ DEPENDENCIES
sinatra sinatra
sinatra-contrib sinatra-contrib
travis-api! travis-api!
travis-config (~> 0.1.0)
travis-core! travis-core!
travis-sidekiqs! travis-sidekiqs!
travis-support! travis-support!

View File

@ -1,2 +1,2 @@
web: bin/start-nginx bundle exec ./script/server web: bundle exec ./script/server
console: bundle exec ./script/console console: bundle exec ./script/console

View File

@ -1,8 +1,9 @@
require 'bundler/setup' require 'bundler/setup'
CORE_PATH = Gem.loaded_specs['travis-core'].full_gem_path require 'travis'
ENV['DB_STRUCTURE'] = "#{CORE_PATH}/db/structure.sql" require 'travis/engine'
begin begin
ENV['SCHEMA'] = File.expand_path('../db/schema.rb', $:.detect { |p| p.include?('travis-core') })
require 'micro_migrations' require 'micro_migrations'
rescue LoadError rescue LoadError
# we can't load micro migrations on production # we can't load micro migrations on production
@ -17,17 +18,6 @@ rescue LoadError
warn "could not load rspec" warn "could not load rspec"
end end
desc "move travis-core-specific migrations to db/migrate"
task 'mv_migrations' do
require 'fileutils'
migration_files = Dir["#{CORE_PATH}/spec/migrations/**/*.rb"]
migration_files.each do |f|
dest = 'db/migrate'
FileUtils.mkdir_p dest
FileUtils.cp f, dest
end
end
desc "generate gemspec" desc "generate gemspec"
task 'travis-api.gemspec' do task 'travis-api.gemspec' do
content = File.read 'travis-api.gemspec' content = File.read 'travis-api.gemspec'
@ -52,3 +42,86 @@ task default: 'travis-api.gemspec'
tasks_path = File.expand_path('../lib/tasks/*.rake', __FILE__) tasks_path = File.expand_path('../lib/tasks/*.rake', __FILE__)
Dir.glob(tasks_path).each { |r| import r } Dir.glob(tasks_path).each { |r| import r }
module ActiveRecord
class Migration
class << self
attr_accessor :disable_ddl_transaction
end
# Disable DDL transactions for this migration.
def self.disable_ddl_transaction!
@disable_ddl_transaction = true
end
def disable_ddl_transaction # :nodoc:
self.class.disable_ddl_transaction
end
end
class Migrator
def use_transaction?(migration)
!migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
end
def ddl_transaction(migration, &block)
if use_transaction?(migration)
Base.transaction { block.call }
else
block.call
end
end
def migrate(&block)
current = migrations.detect { |m| m.version == current_version }
target = migrations.detect { |m| m.version == @target_version }
if target.nil? && @target_version && @target_version > 0
raise UnknownMigrationVersionError.new(@target_version)
end
start = up? ? 0 : (migrations.index(current) || 0)
finish = migrations.index(target) || migrations.size - 1
runnable = migrations[start..finish]
# skip the last migration if we're headed down, but not ALL the way down
runnable.pop if down? && target
ran = []
runnable.each do |migration|
if block && !block.call(migration)
next
end
Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
seen = migrated.include?(migration.version.to_i)
# On our way up, we skip migrating the ones we've already migrated
next if up? && seen
# On our way down, we skip reverting the ones we've never migrated
if down? && !seen
migration.announce 'never migrated, skipping'; migration.write
next
end
begin
ddl_transaction(migration) do
migration.migrate(@direction)
record_version_state_after_migrating(migration.version)
end
ran << migration
rescue => e
canceled_msg = Base.connection.supports_ddl_transactions? ? "this and " : ""
raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
end
end
ran
end
end
class MigrationProxy
delegate :disable_ddl_transaction, to: :migration
end
end

View File

@ -1,43 +0,0 @@
daemon off;
#Heroku dynos have 4 cores.
worker_processes 4;
events {
use epoll;
accept_mutex on;
worker_connections 1024;
}
http {
gzip on;
gzip_comp_level 2;
gzip_min_length 512;
log_format l2met 'measure.nginx.service=$request_time request_id=$http_heroku_request_id';
access_log logs/nginx/access.log l2met;
error_log logs/nginx/error.log;
include mime.types;
default_type application/octet-stream;
sendfile on;
#Must read the body in 5 seconds.
client_body_timeout 5;
upstream app_server {
server unix:/tmp/nginx.socket fail_timeout=0;
}
server {
listen <%= ENV["PORT"] %>;
server_name _;
keepalive_timeout 5;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
}
}

View File

@ -55,7 +55,7 @@ module Travis::Api
def self.setup(options = {}) def self.setup(options = {})
setup! unless setup? setup! unless setup?
Endpoint.set(options) if options Endpoint.set(options) if options
FileUtils.touch('/tmp/app-initialized') FileUtils.touch('/tmp/app-initialized') if ENV['DYNO'] # Heroku
end end
def self.new(options = {}) def self.new(options = {})
@ -87,8 +87,8 @@ module Travis::Api
[ 420, {}, ['Enhance Your Calm']] [ 420, {}, ['Enhance Your Calm']]
end end
use Travis::Api::App::Cors use Travis::Api::App::Cors # if Travis.env == 'development' ???
use Raven::Rack if Endpoint.production? use Raven::Rack if Endpoint.production? && Travis.config.sentry.dsn
use Rack::Protection::PathTraversal use Rack::Protection::PathTraversal
use Rack::SSL if Endpoint.production? use Rack::SSL if Endpoint.production?
use ActiveRecord::ConnectionAdapters::ConnectionManagement use ActiveRecord::ConnectionAdapters::ConnectionManagement
@ -106,6 +106,7 @@ module Travis::Api
use Rack::JSONP use Rack::JSONP
use Rack::Config do |env| use Rack::Config do |env|
env['SCRIPT_NAME'] = env['HTTP_X_SCRIPT_NAME'].to_s + env['SCRIPT_NAME'].to_s
env['travis.global_prefix'] = env['SCRIPT_NAME'] env['travis.global_prefix'] = env['SCRIPT_NAME']
end end
@ -113,6 +114,7 @@ module Travis::Api
use Travis::Api::App::Middleware::Logging use Travis::Api::App::Middleware::Logging
use Travis::Api::App::Middleware::Metriks use Travis::Api::App::Middleware::Metriks
use Travis::Api::App::Middleware::Rewrite use Travis::Api::App::Middleware::Rewrite
use Travis::Api::App::Middleware::UserAgentTracker
SettingsEndpoint.subclass :env_vars SettingsEndpoint.subclass :env_vars
if Travis.config.endpoints.ssh_key if Travis.config.endpoints.ssh_key
@ -180,18 +182,11 @@ module Travis::Api
def self.setup_monitoring def self.setup_monitoring
Raven.configure do |config| Raven.configure do |config|
config.dsn = Travis.config.sentry.dsn config.dsn = Travis.config.sentry.dsn
end if Travis.config.sentry end if Travis.config.sentry.dsn
Travis::LogSubscriber::ActiveRecordMetrics.attach Travis::LogSubscriber::ActiveRecordMetrics.attach
Travis::Notification.setup(instrumentation: false) Travis::Notification.setup(instrumentation: false)
Travis::Metrics.setup
if Travis.config.librato
email, token, source = Travis.config.librato.email,
Travis.config.librato.token,
Travis.config.librato_source
on_error = proc {|ex| puts "librato error: #{ex.message} (#{ex.response.body})"}
Metriks::LibratoMetricsReporter.new(email, token, source: source, on_error: on_error).start
end
end end
def self.load_endpoints def self.load_endpoints

View File

@ -14,7 +14,7 @@ class Travis::Api::App
options // do options // do
headers['Access-Control-Allow-Methods'] = "HEAD, GET, POST, PATCH, PUT, DELETE" headers['Access-Control-Allow-Methods'] = "HEAD, GET, POST, PATCH, PUT, DELETE"
headers['Access-Control-Allow-Headers'] = "Content-Type, Authorization, Accept, If-None-Match, If-Modified-Since" headers['Access-Control-Allow-Headers'] = "Content-Type, Authorization, Accept, If-None-Match, If-Modified-Since, X-User-Agent"
end end
end end
end end

View File

@ -128,7 +128,8 @@ class Travis::Api::App
# token is being received. # token is being received.
get '/post_message', scope: :public do get '/post_message', scope: :public do
content_type :html content_type :html
erb :container data = { check_third_party_cookies: !Travis.config.auth.disable_third_party_cookies_check }
erb(:container, locals: data)
end end
get '/post_message/iframe', scope: :public do get '/post_message/iframe', scope: :public do
@ -216,6 +217,10 @@ class Travis::Api::App
def info(attributes = {}) def info(attributes = {})
info = data.to_hash.slice('name', 'login', 'gravatar_id') info = data.to_hash.slice('name', 'login', 'gravatar_id')
info.merge! attributes.stringify_keys info.merge! attributes.stringify_keys
if Travis::Features.feature_active?(:education_data_sync) ||
(user && Travis::Features.owner_active?(:education_data_sync, user))
info['education'] = education
end
info['github_id'] ||= data['id'] info['github_id'] ||= data['id']
info info
end end
@ -224,6 +229,10 @@ class Travis::Api::App
user user
end end
def education
Travis::Github::Education.new(token.to_s).student?
end
def fetch def fetch
retried ||= false retried ||= false
info = drop_token ? self.info : self.info(github_oauth_token: token) info = drop_token ? self.info : self.info(github_oauth_token: token)
@ -267,8 +276,8 @@ class Travis::Api::App
user user
end end
def get_token(endoint, values) def get_token(endpoint, values)
response = Faraday.post(endoint, values) response = Faraday.new(ssl: Travis.config.github.ssl).post(endpoint, values)
parameters = Addressable::URI.form_unencode(response.body) parameters = Addressable::URI.form_unencode(response.body)
token_info = parameters.assoc("access_token") token_info = parameters.assoc("access_token")
halt 401, 'could not resolve github token' unless token_info halt 401, 'could not resolve github token' unless token_info
@ -316,7 +325,9 @@ class Travis::Api::App
def target_ok?(target_origin) def target_ok?(target_origin)
return unless uri = Addressable::URI.parse(target_origin) return unless uri = Addressable::URI.parse(target_origin)
if uri.host =~ /\A(.+\.)?travis-ci\.(com|org)\Z/ if allowed_https_targets.include?(uri.host)
uri.scheme == 'https'
elsif uri.host =~ /\A(.+\.)?travis-ci\.(com|org)\Z/
uri.scheme == 'https' uri.scheme == 'https'
elsif uri.host =~ /\A(.+\.)?travis-lite\.com\Z/ elsif uri.host =~ /\A(.+\.)?travis-lite\.com\Z/
uri.scheme == 'https' uri.scheme == 'https'
@ -324,6 +335,10 @@ class Travis::Api::App
uri.port > 1023 uri.port > 1023
end end
end end
def allowed_https_targets
@allowed_https_targets ||= Travis.config.auth.target_origin.to_s.split(',')
end
end end
end end
end end
@ -368,6 +383,7 @@ function main() {
var url = window.location.pathname + '/iframe' + window.location.search; var url = window.location.pathname + '/iframe' + window.location.search;
function thirdPartyCookies(yes, no) { function thirdPartyCookies(yes, no) {
<%= "return no();" unless check_third_party_cookies %>
window.cookiesCheckCallback = function(enabled) { enabled ? yes() : no() }; window.cookiesCheckCallback = function(enabled) { enabled ? yes() : no() };
var img = document.createElement('img'); var img = document.createElement('img');
img.src = "https://third-party-cookies.herokuapp.com/set"; img.src = "https://third-party-cookies.herokuapp.com/set";

View File

@ -0,0 +1,31 @@
require 'travis/api/app'
require 'travis/api/app/endpoint/setting_endpoint'
class Travis::Api::App
class Endpoint
class EnvVars < SettingsEndpoint
define_method(:name) { :env_vars }
define_routes!
def update
data = JSON.parse(request.body.read)[singular_name]
previously_public = record.public?
record.update(data)
# if we update from private to public reset value
if !previously_public && record.public? && data['value'].nil?
record.value = nil
end
if record.valid?
repo_settings.save
respond_with(record, type: singular_name, version: :v2)
else
status 422
respond_with(record, type: :validation_error, version: :v2)
end
end
end
end
end

View File

@ -3,12 +3,15 @@ require 'travis/api/app'
class Travis::Api::App class Travis::Api::App
class Endpoint class Endpoint
class Home < Endpoint class Home < Endpoint
host = Travis.config.client_domain || Travis.config.host
fail "Travis.config.client_domain is not set" unless host or test?
set :prefix, '/' set :prefix, '/'
set :client_config, set :client_config,
host: Travis.config.client_domain, host: host,
shorten_host: Travis.config.shorten_host, shorten_host: Travis.config.shorten_host,
assets: Travis.config.assets, assets: Travis.config.assets,
pusher: { key: Travis.config.pusher.try(:key) }, pusher: (Travis.config.pusher_ws || Travis.config.pusher || {}).to_hash.slice(:scheme, :host, :port, :path, :key),
github: { api_url: GH.current.api_host.to_s, scopes: Travis.config.oauth2.try(:scope).to_s.split(?,) } github: { api_url: GH.current.api_host.to_s, scopes: Travis.config.oauth2.try(:scope).to_s.split(?,) }
# Landing point. Redirects web browsers to [API documentation](#/docs/). # Landing point. Redirects web browsers to [API documentation](#/docs/).

View File

@ -3,6 +3,8 @@ require 'travis/api/app'
class Travis::Api::App class Travis::Api::App
class Endpoint class Endpoint
class Jobs < Endpoint class Jobs < Endpoint
include Helpers::Accept
get '/' do get '/' do
prefer_follower do prefer_follower do
respond_with service(:find_jobs, params) respond_with service(:find_jobs, params)
@ -10,7 +12,14 @@ class Travis::Api::App
end end
get '/:id' do get '/:id' do
respond_with service(:find_job, params) job = service(:find_job, params).run
if job && job.repository
respond_with job
else
json = { error: { message: "The job(#{params[:id]}) couldn't be found" } }
status 404
respond_with json
end
end end
post '/:id/cancel' do post '/:id/cancel' do
@ -49,7 +58,10 @@ class Travis::Api::App
get '/:job_id/log' do get '/:job_id/log' do
resource = service(:find_log, params).run resource = service(:find_log, params).run
if !resource || resource.archived? if (!resource || resource.archived?)
# the way we use responders makes it hard to validate proper format
# automatically here, so we need to check it explicitly
if accepts?('text/plain')
archived_log_path = archive_url("/jobs/#{params[:job_id]}/log.txt") archived_log_path = archive_url("/jobs/#{params[:job_id]}/log.txt")
if params[:cors_hax] if params[:cors_hax]
@ -59,6 +71,9 @@ class Travis::Api::App
else else
redirect archived_log_path, 307 redirect archived_log_path, 307
end end
else
status 406
end
else else
respond_with resource respond_with resource
end end

View File

@ -1,13 +1,18 @@
require 'travis/api/app' require 'travis/api/app'
require 'travis/api/app/services/schedule_request'
class Travis::Api::App class Travis::Api::App
class Endpoint class Endpoint
class Requests < Endpoint class Requests < Endpoint
post '/', scope: :private do
if params[:request] && params[:request][:repository]
respond_with service(:schedule_request, params[:request])
else
# DEPRECATED: this will be removed by 1st of December # DEPRECATED: this will be removed by 1st of December
post '/' do
Metriks.meter("api.request.restart").mark Metriks.meter("api.request.restart").mark
respond_with service(:reset_model, params) respond_with service(:reset_model, params)
end end
end
get '/' do get '/' do
begin begin

View File

@ -9,11 +9,11 @@ class Travis::Api::App
# a new SettingsEndpoint subclass, which will be then used as an endpoint # a new SettingsEndpoint subclass, which will be then used as an endpoint
def subclass(name) def subclass(name)
class_name = name.to_s.camelize class_name = name.to_s.camelize
if Travis::Api::App.const_defined?(class_name) if Travis::Api::App::Endpoint.const_defined?(class_name)
Travis::Api::App.const_get(class_name) Travis::Api::App::Endpoint.const_get(class_name)
else else
klass = create_settings_class(name) klass = create_settings_class(name)
Travis::Api::App.const_set(class_name, klass) Travis::Api::App::Endpoint.const_set(class_name, klass)
klass klass
end end
end end
@ -21,6 +21,11 @@ class Travis::Api::App
def create_settings_class(name) def create_settings_class(name)
klass = Class.new(self) do klass = Class.new(self) do
define_method(:name) { name } define_method(:name) { name }
define_routes!
end
end
def define_routes!
get("/", scope: :private) do index end get("/", scope: :private) do index end
get("/:id", scope: :private) do show end get("/:id", scope: :private) do show end
post("/", scope: :private) do create end post("/", scope: :private) do create end
@ -28,7 +33,6 @@ class Travis::Api::App
delete("/:id", scope: :private) do destroy end delete("/:id", scope: :private) do destroy end
end end
end end
end
# Rails style methods for easy overriding # Rails style methods for easy overriding
def index def index

View File

@ -64,6 +64,10 @@ class Travis::Api::App
end end
end end
def accepts?(mime_type)
accept_entries.any? { |e| e.accepts?(mime_type) }
end
def accept_entries def accept_entries
entries = env['HTTP_ACCEPT'].to_s.delete(' ').to_s.split(',').map { |e| Entry.new(e) } entries = env['HTTP_ACCEPT'].to_s.delete(' ').to_s.split(',').map { |e| Entry.new(e) }
entries.empty? ? [Entry.new('*/*')] : entries.sort entries.empty? ? [Entry.new('*/*')] : entries.sort

View File

@ -8,14 +8,16 @@ class Travis::Api::App
module RespondWith module RespondWith
include Accept include Accept
STATUS = {
success: 200,
not_found: 404
}
def respond_with(resource, options = {}) def respond_with(resource, options = {})
result = respond(resource, options) result = respond(resource, options)
if result && response.content_type =~ /application\/json/ if result && response.content_type =~ /application\/json/
if !params[:pretty].nil? && (params[:pretty].downcase == 'true' || params[:pretty].to_i > 0) status STATUS[result[:result]] if result.is_a?(Hash) && result[:result].is_a?(Symbol)
result = JSON.pretty_generate(result) result = prettify_result? ? JSON.pretty_generate(result) : result.to_json
else
result = result.to_json
end
end end
halt result || 404 halt result || 404
end end
@ -48,6 +50,10 @@ class Travis::Api::App
response || (resource ? error(406) : error(404)) response || (resource ? error(406) : error(404))
end end
def prettify_result?
!params[:pretty].nil? && (params[:pretty].downcase == 'true' || params[:pretty].to_i > 0)
end
def apply_service_responder(resource, options) def apply_service_responder(resource, options)
responder = Responders::Service.new(self, resource, options) responder = Responders::Service.new(self, resource, options)
resource = responder.apply if responder.apply? resource = responder.apply if responder.apply?

View File

@ -0,0 +1,62 @@
require 'travis/api/app'
require 'useragent'
class Travis::Api::App
class Middleware
class UserAgentTracker < Middleware
WEB_BROWSERS = [
"Internet Explorer",
"Webkit", "Chrome", "Safari", "Android",
"Firefox", "Camino", "Iceweasel", "Seamonkey", "Android",
"Opera", "Mozilla"
]
before(agent: /^$/) do
::Metriks.meter("api.user_agent.missing").mark
halt(400, "error" => "missing User-Agent header") if Travis::Features.feature_active?(:require_user_agent)
end
before(agent: /^.+$/) do
agent = UserAgent.parse(request.user_agent)
case agent.browser
when *WEB_BROWSERS then mark_browser
when "curl", "Wget" then mark(:console, agent.browser)
when "travis-api-wrapper" then mark(:script, :node_js, agent.browser)
when "TravisPy" then mark(:script, :python, agent.browser)
when "Ruby", "PHP", "Perl", "Python" then mark(:script, agent.browser, :vanilla)
when "Faraday" then mark(:script, :ruby, :vanilla)
when "Travis" then mark_travis(agent)
else mark_unknown
end
end
def mark_browser
# allows a JavaScript Client to set X-User-Agent, for instance to "travis-web" in travis-web
x_agent = UserAgent.parse(env['HTTP_X_USER_AGENT'] || 'unknown').browser
mark(:browser, x_agent)
end
def mark_travis(agent)
command = agent.application.comment.detect { |c| c.start_with? "command " }
if command
mark(:cli, :version, agent.version)
mark(:cli, command.sub(' ', '.'))
else
# only track ruby version and library version for non-cli usage
mark(:script, :ruby, :travis, :version, agent.version)
end
end
def mark_unknown
logger.warn "[user-agent-tracker] Unknown User-Agent: %p" % request.user_agent
mark(:unknown)
end
def mark(*keys)
key = "api.user_agent." << keys.map { |k| k.to_s.downcase.gsub(/[^a-z0-9\-\.]+/, '_') }.join('.')
::Metriks.meter(key).mark
end
end
end
end

View File

@ -56,7 +56,7 @@ module Travis::Api
# If it's nil we also pass it but yield not_found. # If it's nil we also pass it but yield not_found.
def normalize(result) def normalize(result)
case result case result
when String, true, false when Symbol, String, true, false
{ result: result } { result: result }
else else
result result

View File

@ -0,0 +1,52 @@
require 'multi_json'
require 'travis/sidekiq/build_request'
require 'travis/services/base'
class Travis::Api::App
module Services
class ScheduleRequest < Travis::Services::Base
register :schedule_request
def run
repo && active? ? schedule_request : not_found
end
def messages
@messages ||= []
end
private
def schedule_request
Metriks.meter('api.request.create').mark
Travis::Sidekiq::BuildRequest.perform_async(type: 'api', payload: payload, credentials: {})
messages << { notice: 'Build request scheduled.' }
:success
end
def not_found
messages << { error: "Repository #{slug} not found." }
:not_found
end
def active?
Travis::Features.owner_active?(:request_create, repo.owner)
end
def payload
data = params.merge(user: { id: current_user.id })
data[:repository][:id] = repo.github_id
MultiJson.encode(data)
end
def repo
@repo ||= Repository.by_slug(slug).first
end
def slug
repo = params[:repository] || {}
repo.values_at(:owner_name, :name).join('/')
end
end
end
end

View File

@ -37,7 +37,10 @@ module Travis
end end
def log_parts def log_parts
log.parts.sort_by(&:number).map do |part| parts = log.parts
parts = parts.where(number: part_numbers) if part_numbers
parts = parts.where(["number > ?", after]) if after
parts.sort_by(&:number).map do |part|
{ {
'id' => part.id, 'id' => part.id,
'number' => part.number, 'number' => part.number,
@ -46,6 +49,17 @@ module Travis
} }
end end
end end
def after
after = options['after'].to_i
after == 0 ? nil : after
end
def part_numbers
if numbers = options['part_numbers']
numbers.is_a?(String) ? numbers.split(',').map(&:to_i) : numbers
end
end
end end
end end
end end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="98" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="98" height="18" fill="#555"/><rect rx="4" x="37" width="61" height="18" fill="#9f9f9f"/><path fill="#9f9f9f" d="M37 0h4v18h-4z"/><rect rx="4" width="98" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="19.5" y="13" fill="#010101" fill-opacity=".3">build</text><text x="19.5" y="12">build</text><text x="66.5" y="13" fill="#010101" fill-opacity=".3">canceled</text><text x="66.5" y="12">canceled</text></g></svg> <svg xmlns="http://www.w3.org/2000/svg" width="97" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="97" height="18" fill="#555"/><rect rx="4" x="37" width="60" height="18" fill="#9f9f9f"/><path fill="#9f9f9f" d="M37 0h4v18h-4z"/><rect rx="4" width="97" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="19.5" y="14" fill="#010101" fill-opacity=".3">build</text><text x="19.5" y="13">build</text><text x="66" y="14" fill="#010101" fill-opacity=".3">canceled</text><text x="66" y="13">canceled</text></g></svg>

Before

Width:  |  Height:  |  Size: 824 B

After

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 932 B

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="76" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="76" height="18" fill="#555"/><rect rx="4" x="37" width="39" height="18" fill="#9f9f9f"/><path fill="#9f9f9f" d="M37 0h4v18h-4z"/><rect rx="4" width="76" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="19.5" y="13" fill="#010101" fill-opacity=".3">build</text><text x="19.5" y="12">build</text><text x="55.5" y="13" fill="#010101" fill-opacity=".3">error</text><text x="55.5" y="12">error</text></g></svg> <svg xmlns="http://www.w3.org/2000/svg" width="76" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="76" height="18" fill="#555"/><rect rx="4" x="37" width="39" height="18" fill="#9f9f9f"/><path fill="#9f9f9f" d="M37 0h4v18h-4z"/><rect rx="4" width="76" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="19.5" y="14" fill="#010101" fill-opacity=".3">build</text><text x="19.5" y="13">build</text><text x="55.5" y="14" fill="#010101" fill-opacity=".3">error</text><text x="55.5" y="13">error</text></g></svg>

Before

Width:  |  Height:  |  Size: 818 B

After

Width:  |  Height:  |  Size: 818 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="81" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="81" height="18" fill="#555"/><rect rx="4" x="37" width="44" height="18" fill="#e05d44"/><path fill="#e05d44" d="M37 0h4v18h-4z"/><rect rx="4" width="81" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="19.5" y="13" fill="#010101" fill-opacity=".3">build</text><text x="19.5" y="12">build</text><text x="58" y="13" fill="#010101" fill-opacity=".3">failing</text><text x="58" y="12">failing</text></g></svg> <svg xmlns="http://www.w3.org/2000/svg" width="81" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="81" height="18" fill="#555"/><rect rx="4" x="37" width="44" height="18" fill="#e05d44"/><path fill="#e05d44" d="M37 0h4v18h-4z"/><rect rx="4" width="81" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="19.5" y="14" fill="#010101" fill-opacity=".3">build</text><text x="19.5" y="13">build</text><text x="58" y="14" fill="#010101" fill-opacity=".3">failing</text><text x="58" y="13">failing</text></g></svg>

Before

Width:  |  Height:  |  Size: 818 B

After

Width:  |  Height:  |  Size: 818 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="90" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="90" height="18" fill="#555"/><rect rx="4" x="37" width="53" height="18" fill="#4c1"/><path fill="#4c1" d="M37 0h4v18h-4z"/><rect rx="4" width="90" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="19.5" y="13" fill="#010101" fill-opacity=".3">build</text><text x="19.5" y="12">build</text><text x="62.5" y="13" fill="#010101" fill-opacity=".3">passing</text><text x="62.5" y="12">passing</text></g></svg> <svg xmlns="http://www.w3.org/2000/svg" width="90" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="90" height="18" fill="#555"/><rect rx="4" x="37" width="53" height="18" fill="#4c1"/><path fill="#4c1" d="M37 0h4v18h-4z"/><rect rx="4" width="90" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="19.5" y="14" fill="#010101" fill-opacity=".3">build</text><text x="19.5" y="13">build</text><text x="62.5" y="14" fill="#010101" fill-opacity=".3">passing</text><text x="62.5" y="13">passing</text></g></svg>

Before

Width:  |  Height:  |  Size: 816 B

After

Width:  |  Height:  |  Size: 816 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="92" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="92" height="18" fill="#555"/><rect rx="4" x="37" width="55" height="18" fill="#dfb317"/><path fill="#dfb317" d="M37 0h4v18h-4z"/><rect rx="4" width="92" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="19.5" y="13" fill="#010101" fill-opacity=".3">build</text><text x="19.5" y="12">build</text><text x="63.5" y="13" fill="#010101" fill-opacity=".3">pending</text><text x="63.5" y="12">pending</text></g></svg> <svg xmlns="http://www.w3.org/2000/svg" width="92" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="92" height="18" fill="#555"/><rect rx="4" x="37" width="55" height="18" fill="#dfb317"/><path fill="#dfb317" d="M37 0h4v18h-4z"/><rect rx="4" width="92" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="19.5" y="14" fill="#010101" fill-opacity=".3">build</text><text x="19.5" y="13">build</text><text x="63.5" y="14" fill="#010101" fill-opacity=".3">pending</text><text x="63.5" y="13">pending</text></g></svg>

Before

Width:  |  Height:  |  Size: 822 B

After

Width:  |  Height:  |  Size: 822 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="98" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="98" height="18" fill="#555"/><rect rx="4" x="37" width="61" height="18" fill="#9f9f9f"/><path fill="#9f9f9f" d="M37 0h4v18h-4z"/><rect rx="4" width="98" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="19.5" y="13" fill="#010101" fill-opacity=".3">build</text><text x="19.5" y="12">build</text><text x="66.5" y="13" fill="#010101" fill-opacity=".3">unknown</text><text x="66.5" y="12">unknown</text></g></svg> <svg xmlns="http://www.w3.org/2000/svg" width="98" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="98" height="18" fill="#555"/><rect rx="4" x="37" width="61" height="18" fill="#9f9f9f"/><path fill="#9f9f9f" d="M37 0h4v18h-4z"/><rect rx="4" width="98" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="19.5" y="14" fill="#010101" fill-opacity=".3">build</text><text x="19.5" y="13">build</text><text x="66.5" y="14" fill="#010101" fill-opacity=".3">unknown</text><text x="66.5" y="13">unknown</text></g></svg>

Before

Width:  |  Height:  |  Size: 822 B

After

Width:  |  Height:  |  Size: 822 B

26
script/repos_stats.rb Normal file
View File

@ -0,0 +1,26 @@
$stdout.sync = true
Repository.where('last_build_finished_at is not null').count(group: :github_language)
rates = Repository.where('last_build_finished_at is not null').count(group: [:last_build_state, :github_language])
groups = rates.group_by { |k, v| k[1] }
stats = groups.map do |lang, values|
values.inject({ "language" => lang || 'unknown' }) do |result, (state, count)|
result.merge(state[0] => count)
end
end
keys = %w(language total passed failed errored cancelled)
puts keys.join(',')
rows = stats.map do |stat|
values = stat.values
row = [values.shift]
row << stat.values[1..-1].inject(&:+)
keys[1..-1].each { |key| row << (stat[key] || 0) }
row
end
rows = rows.sort_by { |row| row[1] }.reverse
csv = rows.map { |row| row.join(',') }
puts csv.join("\n")

View File

@ -3,6 +3,6 @@ cd "$(dirname "$0")/.."
[ $PORT ] || PORT=3000 [ $PORT ] || PORT=3000
[ $RACK_ENV ] || RACK_ENV=development [ $RACK_ENV ] || RACK_ENV=development
cmd="ruby -I lib -S bundle exec ruby -I lib -S unicorn config.ru -E $RACK_ENV -c config/unicorn.rb" cmd="ruby -I lib -S bundle exec ruby -I lib -S unicorn config.ru -p $PORT -E $RACK_ENV -c config/unicorn.rb"
[[ $RACK_ENV == "development" ]] && exec rerun "$cmd -l 127.0.0.1:$PORT" [[ $RACK_ENV == "development" ]] && exec rerun "$cmd -l 127.0.0.1:$PORT"
exec $cmd exec $cmd

View File

@ -29,7 +29,7 @@ describe Travis::Api::App::SettingsEndpoint do
end end
after do after do
Travis::Api::App.send :remove_const, :Items Travis::Api::App::Endpoint.send :remove_const, :Items
Travis::Api::V2::Http.send :remove_const, :Items Travis::Api::V2::Http.send :remove_const, :Items
Travis::Api::V2::Http.send :remove_const, :Item Travis::Api::V2::Http.send :remove_const, :Item
end end
@ -69,7 +69,7 @@ describe Travis::Api::App::SettingsEndpoint do
response = get '/settings/items', { repository_id: repo.id }, headers response = get '/settings/items', { repository_id: repo.id }, headers
json = JSON.parse(response.body) json = JSON.parse(response.body)
json['items'].should have(1).items json['items'].length.should == 1
item = json['items'].first item = json['items'].first
item['name'].should == 'an item' item['name'].should == 'an item'
item['id'].should_not be_nil item['id'].should_not be_nil
@ -165,7 +165,7 @@ describe Travis::Api::App::SettingsEndpoint do
json['item']['id'].should == item.id json['item']['id'].should == item.id
json['item'].should_not have_key('secret') json['item'].should_not have_key('secret')
repo.reload.settings.items.should have(0).items repo.reload.settings.items.length.should == 0
end end
it 'returns 404 if item can\'t be found' do it 'returns 404 if item can\'t be found' do

View File

@ -24,7 +24,7 @@ describe Travis::Api::App::SettingsEndpoint do
end end
after do after do
Travis::Api::App.send :remove_const, :Item Travis::Api::App::Endpoint.send :remove_const, :Item
Travis::Api::V2::Http.send :remove_const, :Item Travis::Api::V2::Http.send :remove_const, :Item
end end

View File

@ -37,7 +37,7 @@ describe 'Hooks' do
GH.stubs(:[]).returns([]) GH.stubs(:[]).returns([])
GH.expects(:post).with(target, payload).returns(GH.load(PAYLOADS[:github][:hook_active])) GH.expects(:post).with(target, payload).returns(GH.load(PAYLOADS[:github][:hook_active]))
response = put 'hooks', { hook: { id: hook.id, active: 'true' } }, headers response = put 'hooks', { hook: { id: hook.id, active: 'true' } }, headers
repo.reload.active?.should be_true repo.reload.active?.should == true
response.should be_successful response.should be_successful
end end
end end

View File

@ -28,6 +28,7 @@ describe 'Jobs' do
context 'when log is archived' do context 'when log is archived' do
it 'redirects to archive' do it 'redirects to archive' do
job.log.update_attributes!(content: 'the log', archived_at: Time.now, archive_verified: true) job.log.update_attributes!(content: 'the log', archived_at: Time.now, archive_verified: true)
headers = { 'HTTP_ACCEPT' => 'text/plain; version=2' }
response = get "/jobs/#{job.id}/log.txt", {}, headers response = get "/jobs/#{job.id}/log.txt", {}, headers
response.should redirect_to("https://s3.amazonaws.com/archive.travis-ci.org/jobs/#{job.id}/log.txt") response.should redirect_to("https://s3.amazonaws.com/archive.travis-ci.org/jobs/#{job.id}/log.txt")
end end
@ -36,6 +37,7 @@ describe 'Jobs' do
context 'when log is missing' do context 'when log is missing' do
it 'redirects to archive' do it 'redirects to archive' do
job.log.destroy job.log.destroy
headers = { 'HTTP_ACCEPT' => 'text/plain; version=2' }
response = get "/jobs/#{job.id}/log.txt", {}, headers response = get "/jobs/#{job.id}/log.txt", {}, headers
response.should redirect_to("https://s3.amazonaws.com/archive.travis-ci.org/jobs/#{job.id}/log.txt") response.should redirect_to("https://s3.amazonaws.com/archive.travis-ci.org/jobs/#{job.id}/log.txt")
end end
@ -44,6 +46,7 @@ describe 'Jobs' do
context 'with cors_hax param' do context 'with cors_hax param' do
it 'renders No Content response with location of the archived log' do it 'renders No Content response with location of the archived log' do
job.log.destroy job.log.destroy
headers = { 'HTTP_ACCEPT' => 'text/plain; version=2' }
response = get "/jobs/#{job.id}/log.txt?cors_hax=true", {}, headers response = get "/jobs/#{job.id}/log.txt?cors_hax=true", {}, headers
response.status.should == 204 response.status.should == 204
response.headers['Location'].should == "https://s3.amazonaws.com/archive.travis-ci.org/jobs/#{job.id}/log.txt" response.headers['Location'].should == "https://s3.amazonaws.com/archive.travis-ci.org/jobs/#{job.id}/log.txt"
@ -51,9 +54,35 @@ describe 'Jobs' do
end end
context 'with chunked log requested' do context 'with chunked log requested' do
it 'responds with 406 when log is already aggregated' do it 'responds with only selected chunks if after is specified' do
job.log.update_attributes(aggregated_at: Time.now) job.log.parts << Log::Part.new(content: 'foo', number: 1, final: false)
job.log.parts << Log::Part.new(content: 'bar', number: 2, final: true)
job.log.parts << Log::Part.new(content: 'bar', number: 3, final: true)
headers = { 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json; chunked=true' } headers = { 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json; chunked=true' }
response = get "/jobs/#{job.id}/log", { after: 1 }, headers
body = JSON.parse(response.body)
body['log']['parts'].map { |p| p['number'] }.sort.should == [2, 3]
end
it 'responds with only selected chunks if part_numbers are requested' do
job.log.parts << Log::Part.new(content: 'foo', number: 1, final: false)
job.log.parts << Log::Part.new(content: 'bar', number: 2, final: true)
job.log.parts << Log::Part.new(content: 'bar', number: 3, final: true)
headers = { 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json; chunked=true' }
response = get "/jobs/#{job.id}/log", { part_numbers: '1,3,4' }, headers
body = JSON.parse(response.body)
body['log']['parts'].map { |p| p['number'] }.sort.should == [1, 3]
end
it 'responds with 406 when log is already aggregated' do
job.log.update_attributes(aggregated_at: Time.now, archived_at: Time.now, archive_verified: true)
job.log.should be_archived
headers = { 'HTTP_ACCEPT' => 'application/json; version=2; chunked=true' }
response = get "/jobs/#{job.id}/log", {}, headers response = get "/jobs/#{job.id}/log", {}, headers
response.status.should == 406 response.status.should == 406
end end

View File

@ -21,9 +21,12 @@ describe Travis::Api::App::SettingsEndpoint do
json = JSON.parse(response.body) json = JSON.parse(response.body)
json['env_var']['name'].should == 'FOO' json['env_var']['name'].should == 'FOO'
json['env_var']['id'].should == record.id json['env_var']['id'].should == record.id
json['env_var']['public'].should be_false json['env_var']['public'].should == false
json['env_var']['repository_id'].should == repo.id json['env_var']['repository_id'].should == repo.id
json['env_var'].should_not have_key('value')
# TODO not sure why this has changed, and if it is harmful. the settings UI looks correct to me on staging
# json['env_var'].should_not have_key('value')
json['env_var']['value'].should be_nil
end end
it 'returns 404 if env var can\'t be found' do it 'returns 404 if env var can\'t be found' do
@ -47,8 +50,10 @@ describe Travis::Api::App::SettingsEndpoint do
key['name'].should == 'FOO' key['name'].should == 'FOO'
key['id'].should == record.id key['id'].should == record.id
key['repository_id'].should == repo.id key['repository_id'].should == repo.id
key['public'].should be_false
key.should_not have_key('value') key['public'].should == false
# key.should_not have_key('value')
key['value'].should be_nil
end end
end end
@ -59,7 +64,8 @@ describe Travis::Api::App::SettingsEndpoint do
json = JSON.parse(response.body) json = JSON.parse(response.body)
json['env_var']['name'].should == 'FOO' json['env_var']['name'].should == 'FOO'
json['env_var']['id'].should_not be_nil json['env_var']['id'].should_not be_nil
json['env_var'].should_not have_key('value') # json['env_var'].should_not have_key('value')
json['env_var']['value'].should be_nil
env_var = repo.reload.settings.env_vars.first env_var = repo.reload.settings.env_vars.first
env_var.id.should_not be_nil env_var.id.should_not be_nil
@ -83,6 +89,34 @@ describe Travis::Api::App::SettingsEndpoint do
end end
describe 'PATCH /settings/env_vars/:id' do describe 'PATCH /settings/env_vars/:id' do
it 'resets value if private key is made public unless new value is provided' do
settings = repo.settings
env_var = settings.env_vars.create(name: 'FOO', value: 'bar')
settings.save
body = { env_var: { public: true, value: 'a new value' } }.to_json
response = patch "/settings/env_vars/#{env_var.id}?repository_id=#{repo.id}", body, headers
json = JSON.parse(response.body)
json['env_var']['value'].should == 'a new value'
updated_env_var = repo.reload.settings.env_vars.find(env_var.id)
updated_env_var.value.decrypt.should == 'a new value'
end
it 'resets value if private key is made public' do
settings = repo.settings
env_var = settings.env_vars.create(name: 'FOO', value: 'bar')
settings.save
body = { env_var: { public: true } }.to_json
response = patch "/settings/env_vars/#{env_var.id}?repository_id=#{repo.id}", body, headers
json = JSON.parse(response.body)
json['env_var']['value'].should be_nil
updated_env_var = repo.reload.settings.env_vars.find(env_var.id)
updated_env_var.value.decrypt.should be_nil
end
it 'should update a key' do it 'should update a key' do
settings = repo.settings settings = repo.settings
env_var = settings.env_vars.create(name: 'FOO', value: 'bar') env_var = settings.env_vars.create(name: 'FOO', value: 'bar')
@ -93,7 +127,8 @@ describe Travis::Api::App::SettingsEndpoint do
json = JSON.parse(response.body) json = JSON.parse(response.body)
json['env_var']['name'].should == 'FOO' json['env_var']['name'].should == 'FOO'
json['env_var']['id'].should == env_var.id json['env_var']['id'].should == env_var.id
json['env_var'].should_not have_key('value') # json['env_var'].should_not have_key('value')
json['env_var']['value'].should be_nil
updated_env_var = repo.reload.settings.env_vars.find(env_var.id) updated_env_var = repo.reload.settings.env_vars.find(env_var.id)
updated_env_var.id.should == env_var.id updated_env_var.id.should == env_var.id
@ -135,9 +170,10 @@ describe Travis::Api::App::SettingsEndpoint do
json = JSON.parse(response.body) json = JSON.parse(response.body)
json['env_var']['name'].should == 'FOO' json['env_var']['name'].should == 'FOO'
json['env_var']['id'].should == env_var.id json['env_var']['id'].should == env_var.id
json['env_var'].should_not have_key('value') # json['env_var'].should_not have_key('value')
json['env_var']['value'].should be_nil
repo.reload.settings.env_vars.should have(0).env_vars repo.reload.settings.env_vars.length.should == 0
end end
it 'returns 404 if env_var can\'t be found' do it 'returns 404 if env_var can\'t be found' do

View File

@ -50,7 +50,7 @@ end
RSpec.configure do |c| RSpec.configure do |c|
c.mock_framework = :mocha c.mock_framework = :mocha
c.expect_with :rspec, :stdlib c.expect_with :rspec, :test_unit
c.include TestHelpers c.include TestHelpers
c.before :suite do c.before :suite do

View File

@ -48,7 +48,7 @@ describe Travis::Api::V2::Http::Build do
let(:data) { Travis::Api::V2::Http::Build.new(build).data } let(:data) { Travis::Api::V2::Http::Build.new(build).data }
it 'returns pull request data' do it 'returns pull request data' do
data['build']['pull_request'].should be_true data['build']['pull_request'].should == true
data['build']['pull_request_title'].should == 'A pull request' data['build']['pull_request_title'].should == 'A pull request'
data['build']['pull_request_number'].should == 44 data['build']['pull_request_number'].should == 44
end end
@ -80,7 +80,7 @@ describe 'Travis::Api::V2::Http::Build using Travis::Services::Builds::FindOne'
let(:data) { Travis::Api::V2::Http::Build.new(build).data } let(:data) { Travis::Api::V2::Http::Build.new(build).data }
it 'queries' do it 'queries' do
lambda { data }.should issue_queries(6) lambda { data }.should issue_queries(8)
end end
end end

View File

@ -55,7 +55,7 @@ describe Travis::Api::V2::Http::Builds do
end end
it 'returns pull request data' do it 'returns pull request data' do
data['builds'].first['pull_request'].should be_true data['builds'].first['pull_request'].should == true
data['builds'].first['pull_request_number'].should == 44 data['builds'].first['pull_request_number'].should == 44
end end
end end
@ -71,7 +71,7 @@ describe 'Travis::Api::V2::Http::Builds using Travis::Services::Builds::FindAll'
end end
it 'queries' do it 'queries' do
lambda { data }.should issue_queries(3) lambda { data }.should issue_queries(9)
end end
end end

View File

@ -5,7 +5,7 @@ describe Travis::Api::V2::Http::EnvVar do
let(:data) { Travis::Api::V2::Http::EnvVar.new(env_var) } let(:data) { Travis::Api::V2::Http::EnvVar.new(env_var) }
it 'returns value' do it 'returns value' do
data.as_json[:env_var][:value].should == 'bar' data.as_json['env_var'][:value].should == 'bar'
end end
describe 'private' do describe 'private' do
@ -13,8 +13,8 @@ describe Travis::Api::V2::Http::EnvVar do
it "doesn't return the value" do it "doesn't return the value" do
data.to_json.should_not include('bar') data.to_json.should_not include('bar')
data.as_json[:env_var].should_not have_key(:value) data.as_json['env_var']['value'].should be_nil
data.as_json[:env_var].should_not have_key('value') data.as_json['env_var'][:value].should be_nil
end end
end end
end end

View File

@ -29,5 +29,15 @@ describe Travis::Api::V2::Http::Log do
{ 'id' => 2, 'number' => 2, 'content' => 'bar', 'final' => true } { 'id' => 2, 'number' => 2, 'content' => 'bar', 'final' => true }
] ]
end end
describe "with parts numbers specified" do
let(:data) { described_class.new(log, 'part_numbers' => "1,3", chunked: true).data }
it 'returns only requested parts' do
parts = log.parts.find_all { |p| p.number == 1 }
log.parts.expects(:where).with(number: [1, 3]).returns(parts)
data['log']['parts'].should == [{ 'id' => 1, 'number' => 1, 'content' => 'foo', 'final' => false }]
end
end
end end
end end

View File

@ -44,7 +44,7 @@ describe Travis::Api::App::Cors do
end end
it 'sets Access-Control-Allow-Headers' do it 'sets Access-Control-Allow-Headers' do
headers['Access-Control-Allow-Headers'].should == "Content-Type, Authorization, Accept, If-None-Match, If-Modified-Since" headers['Access-Control-Allow-Headers'].should == "Content-Type, Authorization, Accept, If-None-Match, If-Modified-Since, X-User-Agent"
end end
end end
end end

View File

@ -3,6 +3,10 @@ require 'spec_helper'
describe Travis::Api::App::Endpoint::Authorization::UserManager do describe Travis::Api::App::Endpoint::Authorization::UserManager do
let(:manager) { described_class.new(data, 'abc123') } let(:manager) { described_class.new(data, 'abc123') }
before do
Travis::Features.enable_for_all(:education_data_sync)
end
describe '#info' do describe '#info' do
let(:data) { let(:data) {
{ {
@ -10,16 +14,18 @@ describe Travis::Api::App::Endpoint::Authorization::UserManager do
}.stringify_keys }.stringify_keys
} }
before { manager.stubs(:education).returns(false) }
it 'gets data from github payload' do it 'gets data from github payload' do
manager.info.should == { manager.info.should == {
name: 'Piotr Sarnacki', login: 'drogus', gravatar_id: '123', github_id: 456 name: 'Piotr Sarnacki', login: 'drogus', gravatar_id: '123', github_id: 456, education: false
}.stringify_keys }.stringify_keys
end end
it 'allows to overwrite existing keys' do it 'allows to overwrite existing keys' do
manager.info({login: 'piotr.sarnacki', bar: 'baz'}.stringify_keys).should == { manager.info({login: 'piotr.sarnacki', bar: 'baz'}.stringify_keys).should == {
name: 'Piotr Sarnacki', login: 'piotr.sarnacki', gravatar_id: '123', name: 'Piotr Sarnacki', login: 'piotr.sarnacki', gravatar_id: '123',
github_id: 456, bar: 'baz' github_id: 456, bar: 'baz', education: false
}.stringify_keys }.stringify_keys
end end
end end
@ -34,8 +40,9 @@ describe Travis::Api::App::Endpoint::Authorization::UserManager do
User.expects(:find_by_github_id).with(456).returns(user) User.expects(:find_by_github_id).with(456).returns(user)
manager = described_class.new(data, 'abc123', true) manager = described_class.new(data, 'abc123', true)
manager.stubs(:education).returns(false)
attributes = { login: 'drogus', github_id: 456 }.stringify_keys attributes = { login: 'drogus', github_id: 456, education: false }.stringify_keys
user.expects(:update_attributes).with(attributes) user.expects(:update_attributes).with(attributes)
@ -46,8 +53,9 @@ describe Travis::Api::App::Endpoint::Authorization::UserManager do
it 'updates user data' do it 'updates user data' do
user = stub('user', login: 'drogus', github_id: 456) user = stub('user', login: 'drogus', github_id: 456)
User.expects(:find_by_github_id).with(456).returns(user) User.expects(:find_by_github_id).with(456).returns(user)
attributes = { login: 'drogus', github_id: 456, github_oauth_token: 'abc123' }.stringify_keys attributes = { login: 'drogus', github_id: 456, github_oauth_token: 'abc123', education: false }.stringify_keys
user.expects(:update_attributes).with(attributes) user.expects(:update_attributes).with(attributes)
manager.stubs(:education).returns(false)
manager.fetch.should == user manager.fetch.should == user
end end
@ -57,11 +65,23 @@ describe Travis::Api::App::Endpoint::Authorization::UserManager do
it 'creates new user' do it 'creates new user' do
user = stub('user', login: 'drogus', github_id: 456) user = stub('user', login: 'drogus', github_id: 456)
User.expects(:find_by_github_id).with(456).returns(nil) User.expects(:find_by_github_id).with(456).returns(nil)
attributes = { login: 'drogus', github_id: 456, github_oauth_token: 'abc123' }.stringify_keys attributes = { login: 'drogus', github_id: 456, github_oauth_token: 'abc123', education: false }.stringify_keys
User.expects(:create!).with(attributes).returns(user) User.expects(:create!).with(attributes).returns(user)
manager.stubs(:education).returns(false)
manager.fetch.should == user manager.fetch.should == user
end end
end end
end end
describe '#education' do
let(:data) { {} }
it 'runs students check with token' do
education = stub(:education)
education.expects(:student?).returns(true)
Travis::Github::Education.expects(:new).with('abc123').returns(education)
manager.education.should be_truthy
end
end
end end

View File

@ -30,11 +30,11 @@ describe Travis::Api::App::Endpoint::Authorization do
end end
describe 'GET /auth/authorize' do describe 'GET /auth/authorize' do
pending "not yet implemented" skip "not yet implemented"
end end
describe 'POST /auth/access_token' do describe 'POST /auth/access_token' do
pending "not yet implemented" skip "not yet implemented"
end end
describe "GET /auth/handshake" do describe "GET /auth/handshake" do
@ -75,12 +75,16 @@ describe Travis::Api::App::Endpoint::Authorization do
User::Oauth.instance_variable_set("@wanted_scopes", nil) User::Oauth.instance_variable_set("@wanted_scopes", nil)
end end
it 'redirects to insufficient access page' do # in endpoint/authorization.rb 271, get_token faraday raises the exception:
# hostname "foobar.com" does not match the server certificate
# TODO disabling this as per @rkh's advice
xit 'redirects to insufficient access page' do
response = get '/auth/handshake?state=github-state&code=oauth-code' response = get '/auth/handshake?state=github-state&code=oauth-code'
response.should redirect_to('https://travis-ci.org/insufficient_access') response.should redirect_to('https://travis-ci.org/insufficient_access')
end end
it 'redirects to insufficient access page for existing user' do # TODO disabling this as per @rkh's advice
xit 'redirects to insufficient access page for existing user' do
user = mock('user') user = mock('user')
User.expects(:find_by_github_id).with(111).returns(user) User.expects(:find_by_github_id).with(111).returns(user)
expect { expect {

View File

@ -0,0 +1,56 @@
require 'spec_helper'
describe Travis::Api::App::Endpoint::Requests do
include Travis::Testing::Stubs
let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: -1) }
let(:data) { { request: { repository: { owner_name: 'owner', name: 'name' }, branch: 'branch', config: { env: ['FOO=foo'] } } } }
let(:headers) { { 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json, */*; q=0.01', 'HTTP_AUTHORIZATION' => %(token "#{token.token}") } }
let(:response) { post('/requests', data, headers) }
before do
User.stubs(:find_by_github_id).returns(user)
User.stubs(:find).returns(user)
end
describe 'POST to /' do
it 'needs to be authenticated' do
Travis::Api::App::AccessToken.stubs(:find_by_token).returns(nil)
expect(response.status).to eq 403
end
describe 'if the repository does not exist' do
it 'returns 404' do
expect(response.status).to eq 404
end
it 'includes a notice' do
expect(response.body).to eq '{"result":"not_found","flash":[{"error":"Repository owner/name not found."}]}'
end
end
describe 'if successful' do
before do
Repository.stubs(:by_slug).returns([repo])
Travis::Sidekiq::BuildRequest.stubs(:perform_async)
Travis::Features.stubs(:owner_active?).returns(true)
end
it 'returns 200' do
expect(response.status).to eq 200
end
it 'includes a notice' do
expect(response.body).to eq '{"result":"success","flash":[{"notice":"Build request scheduled."}]}'
end
it 'schedules the build request' do
payload = data[:request].merge(user: { id: user.id })
payload[:repository][:id] = repo.github_id
Travis::Sidekiq::BuildRequest.expects(:perform_async).with(type: 'api', payload: MultiJson.encode(payload), credentials: {})
response
end
end
end
end

View File

@ -40,7 +40,7 @@ describe Travis::Api::App::Endpoint::Users do
response = post('/users/sync', { access_token: access_token.to_s }, 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json, */*; q=0.01') response = post('/users/sync', { access_token: access_token.to_s }, 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json, */*; q=0.01')
response.status.should == 409 response.status.should == 409
JSON.parse(response.body).should be_true JSON.parse(response.body).should == { 'message' => 'Sync already in progress. Try again later.' }
end end
end end
end end

View File

@ -47,23 +47,23 @@ module Travis::Api::App::Helpers
describe 'accepts?' do describe 'accepts?' do
it 'accepts everything with */* type' do it 'accepts everything with */* type' do
entry = Accept::Entry.new('*/*') entry = Accept::Entry.new('*/*')
entry.accepts?('application/json').should be_true entry.accepts?('application/json').should == true
entry.accepts?('foo/bar').should be_true entry.accepts?('foo/bar').should == true
end end
it 'accepts every subtype with application/* type' do it 'accepts every subtype with application/* type' do
entry = Accept::Entry.new('application/*') entry = Accept::Entry.new('application/*')
entry.accepts?('application/foo').should be_true entry.accepts?('application/foo').should == true
entry.accepts?('application/bar').should be_true entry.accepts?('application/bar').should == true
entry.accepts?('text/plain').should be_false entry.accepts?('text/plain').should == false
end end
it 'accepts when type and subtype match' do it 'accepts when type and subtype match' do
entry = Accept::Entry.new('application/json') entry = Accept::Entry.new('application/json')
entry.accepts?('application/json').should be_true entry.accepts?('application/json').should == true
entry.accepts?('application/xml').should be_false entry.accepts?('application/xml').should == false
end end
end end
end end

View File

@ -0,0 +1,104 @@
require 'spec_helper'
describe Travis::Api::App::Middleware::UserAgentTracker do
before do
mock_app do
use Travis::Api::App::Middleware::UserAgentTracker
get('/') { 'ok' }
end
end
def expect_meter(name)
Metriks.expects(:meter).with(name).returns(stub("meter", mark: nil))
end
def get(env = {})
env['HTTP_USER_AGENT'] ||= agent if agent
super('/', {}, env)
end
context 'missing User-Agent' do
let(:agent) { }
it "tracks it" do
expect_meter("api.user_agent.missing")
get.should be_ok
end
it "denies request if require_user_agent feature is enabled" do
Travis::Features.expects(:feature_active?).with(:require_user_agent).returns(true)
get.status.should be == 400
end
end
context 'web browser' do
let(:agent) { "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.36 Safari/537.36" }
specify 'without X-User-Agent' do
expect_meter("api.user_agent.browser.unknown")
get
end
specify 'with X-User-Agent' do
expect_meter("api.user_agent.browser.travis-web")
get('HTTP_X_USER_AGENT' => 'travis-web')
end
end
context 'console' do
let(:agent) { 'curl' }
specify do
expect_meter("api.user_agent.console.curl")
get
end
end
context 'travis-api-wrapper' do
let(:agent) { 'travis-api-wrapper - v0.01 - (cmaujean@gmail.com)' }
specify do
expect_meter("api.user_agent.script.node_js.travis-api-wrapper")
get
end
end
context 'TravisPy' do
let(:agent) { 'TravisPy' }
specify do
expect_meter("api.user_agent.script.python.travispy")
get
end
end
context 'Ruby' do
let(:agent) { 'Ruby' }
specify do
expect_meter("api.user_agent.script.ruby.vanilla")
get
end
end
context 'Faraday' do
let(:agent) { 'Faraday' }
specify do
expect_meter("api.user_agent.script.ruby.vanilla")
get
end
end
context 'travis.rb' do
let(:agent) { 'Travis/1.6.8 (Mac OS X 10.9.2 like Darwin; Ruby 2.1.1p42; RubyGems 2.0.14) Faraday/0.8.9 Typhoeus/0.6.7' }
specify do
expect_meter("api.user_agent.script.ruby.travis.version.1.6.8")
get
end
end
context 'Travis CLI' do
let(:agent) { 'Travis/1.6.8 (Mac OS X 10.10.2 like Darwin; Ruby 2.1.1; RubyGems 2.0.14; command whoami) Faraday/0.8.9 Typhoeus/0.6.7' }
specify do
expect_meter("api.user_agent.cli.version.1.6.8")
expect_meter("api.user_agent.cli.command.whoami")
get
end
end
end

View File

@ -14,7 +14,7 @@ module Travis::Api::App::Responders
context 'with resource not associated with Api data class' do context 'with resource not associated with Api data class' do
it 'returns nil result' do it 'returns nil result' do
json.apply.should be_false json.apply.should be_nil
end end
end end
@ -31,8 +31,8 @@ module Travis::Api::App::Responders
let(:resource) { nil } let(:resource) { nil }
it 'responds with 404' do it 'responds with 404' do
json.apply?.should be_false json.apply?.should be_falsey
json.apply.should be_false json.apply.should be_falsey
end end
end end
end end

View File

@ -12,31 +12,33 @@ Gem::Specification.new do |s|
"Piotr Sarnacki", "Piotr Sarnacki",
"Konstantin Haase", "Konstantin Haase",
"Sven Fuchs", "Sven Fuchs",
"Mathias Meyer",
"Hiro Asari", "Hiro Asari",
"Mathias Meyer",
"Josh Kalderimis", "Josh Kalderimis",
"Henrik Hodne", "Henrik Hodne",
"Andre Arko", "Andre Arko",
"Erik Michaels-Ober", "Erik Michaels-Ober",
"Brian Ford", "Dan Buch",
"Steve Richert", "Steve Richert",
"rainsun", "Brian Ford",
"Bryan Goldstein", "Bryan Goldstein",
"James Dennes",
"Nick Schonning",
"Patrick Williams",
"Puneeth Chaganti", "Puneeth Chaganti",
"Thais Camilo and Konstantin Haase", "Thais Camilo and Konstantin Haase",
"Tim Carey-Smith", "Tim Carey-Smith",
"Zachary Scott" "Zachary Scott",
"James Dennes",
"rainsun",
"Dan Rice",
"Nick Schonning",
"Patrick Williams"
] ]
s.email = [ s.email = [
"drogus@gmail.com", "drogus@gmail.com",
"konstantin.mailinglists@googlemail.com", "konstantin.mailinglists@googlemail.com",
"me@svenfuchs.com", "me@svenfuchs.com",
"meyer@paperplanes.de",
"asari.ruby@gmail.com", "asari.ruby@gmail.com",
"meyer@paperplanes.de",
"josh.kalderimis@gmail.com", "josh.kalderimis@gmail.com",
"me@henrikhodne.com", "me@henrikhodne.com",
"henrik@hodne.io", "henrik@hodne.io",
@ -44,16 +46,19 @@ Gem::Specification.new do |s|
"andre@arko.net", "andre@arko.net",
"svenfuchs@artweb-design.de", "svenfuchs@artweb-design.de",
"sferik@gmail.com", "sferik@gmail.com",
"bford@engineyard.com", "dan@travis-ci.org",
"steve.richert@gmail.com", "steve.richert@gmail.com",
"patrick@bittorrent.com", "bford@engineyard.com",
"henrik@travis-ci.com",
"punchagan@muse-amuse.in", "punchagan@muse-amuse.in",
"jdennes@gmail.com",
"nschonni@gmail.com",
"rainsuner@gmail.com", "rainsuner@gmail.com",
"dev+narwen+rkh@rkh.im", "dev+narwen+rkh@rkh.im",
"tim@spork.in", "tim@spork.in",
"e@zzak.io", "e@zzak.io",
"jdennes@gmail.com",
"dan@zoombody.com",
"nschonni@gmail.com",
"patrick@bittorrent.com",
"brysgo@gmail.com" "brysgo@gmail.com"
] ]
@ -65,7 +70,6 @@ Gem::Specification.new do |s|
"bin/start-nginx", "bin/start-nginx",
"config.ru", "config.ru",
"config/database.yml", "config/database.yml",
"config/nginx.conf.erb",
"config/puma-config.rb", "config/puma-config.rb",
"config/unicorn.rb", "config/unicorn.rb",
"lib/tasks/build_update_branch.rake", "lib/tasks/build_update_branch.rake",
@ -83,6 +87,7 @@ Gem::Specification.new do |s|
"lib/travis/api/app/endpoint/builds.rb", "lib/travis/api/app/endpoint/builds.rb",
"lib/travis/api/app/endpoint/documentation.rb", "lib/travis/api/app/endpoint/documentation.rb",
"lib/travis/api/app/endpoint/endpoints.rb", "lib/travis/api/app/endpoint/endpoints.rb",
"lib/travis/api/app/endpoint/env_vars.rb",
"lib/travis/api/app/endpoint/home.rb", "lib/travis/api/app/endpoint/home.rb",
"lib/travis/api/app/endpoint/hooks.rb", "lib/travis/api/app/endpoint/hooks.rb",
"lib/travis/api/app/endpoint/jobs.rb", "lib/travis/api/app/endpoint/jobs.rb",
@ -91,6 +96,7 @@ Gem::Specification.new do |s|
"lib/travis/api/app/endpoint/repos.rb", "lib/travis/api/app/endpoint/repos.rb",
"lib/travis/api/app/endpoint/requests.rb", "lib/travis/api/app/endpoint/requests.rb",
"lib/travis/api/app/endpoint/setting_endpoint.rb", "lib/travis/api/app/endpoint/setting_endpoint.rb",
"lib/travis/api/app/endpoint/singleton_settings_endpoint.rb",
"lib/travis/api/app/endpoint/uptime.rb", "lib/travis/api/app/endpoint/uptime.rb",
"lib/travis/api/app/endpoint/users.rb", "lib/travis/api/app/endpoint/users.rb",
"lib/travis/api/app/extensions.rb", "lib/travis/api/app/extensions.rb",
@ -110,6 +116,7 @@ Gem::Specification.new do |s|
"lib/travis/api/app/middleware/metriks.rb", "lib/travis/api/app/middleware/metriks.rb",
"lib/travis/api/app/middleware/rewrite.rb", "lib/travis/api/app/middleware/rewrite.rb",
"lib/travis/api/app/middleware/scope_check.rb", "lib/travis/api/app/middleware/scope_check.rb",
"lib/travis/api/app/middleware/user_agent_tracker.rb",
"lib/travis/api/app/responders.rb", "lib/travis/api/app/responders.rb",
"lib/travis/api/app/responders/atom.rb", "lib/travis/api/app/responders/atom.rb",
"lib/travis/api/app/responders/badge.rb", "lib/travis/api/app/responders/badge.rb",
@ -119,6 +126,7 @@ Gem::Specification.new do |s|
"lib/travis/api/app/responders/plain.rb", "lib/travis/api/app/responders/plain.rb",
"lib/travis/api/app/responders/service.rb", "lib/travis/api/app/responders/service.rb",
"lib/travis/api/app/responders/xml.rb", "lib/travis/api/app/responders/xml.rb",
"lib/travis/api/app/services/schedule_request.rb",
"lib/travis/api/serializer.rb", "lib/travis/api/serializer.rb",
"lib/travis/api/v2.rb", "lib/travis/api/v2.rb",
"lib/travis/api/v2/http.rb", "lib/travis/api/v2/http.rb",
@ -143,11 +151,13 @@ Gem::Specification.new do |s|
"lib/travis/api/v2/http/request.rb", "lib/travis/api/v2/http/request.rb",
"lib/travis/api/v2/http/requests.rb", "lib/travis/api/v2/http/requests.rb",
"lib/travis/api/v2/http/ssh_key.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/ssl_key.rb",
"lib/travis/api/v2/http/user.rb", "lib/travis/api/v2/http/user.rb",
"lib/travis/api/v2/http/validation_error.rb", "lib/travis/api/v2/http/validation_error.rb",
"lib/travis/private_key.rb",
"public/favicon.ico", "public/favicon.ico",
"public/images/result/canceled.png",
"public/images/result/canceled.svg",
"public/images/result/error.png", "public/images/result/error.png",
"public/images/result/error.svg", "public/images/result/error.svg",
"public/images/result/failing.png", "public/images/result/failing.png",
@ -159,12 +169,14 @@ Gem::Specification.new do |s|
"public/images/result/unknown.png", "public/images/result/unknown.png",
"public/images/result/unknown.svg", "public/images/result/unknown.svg",
"script/console", "script/console",
"script/repos_stats.rb",
"script/server", "script/server",
"spec/integration/formats_handling_spec.rb", "spec/integration/formats_handling_spec.rb",
"spec/integration/responders_spec.rb", "spec/integration/responders_spec.rb",
"spec/integration/routes.backup.rb", "spec/integration/routes.backup.rb",
"spec/integration/scopes_spec.rb", "spec/integration/scopes_spec.rb",
"spec/integration/settings_endpoint_spec.rb", "spec/integration/settings_endpoint_spec.rb",
"spec/integration/singleton_settings_endpoint_spec.rb",
"spec/integration/uptime_spec.rb", "spec/integration/uptime_spec.rb",
"spec/integration/v1/branches_spec.rb", "spec/integration/v1/branches_spec.rb",
"spec/integration/v1/builds_spec.rb", "spec/integration/v1/builds_spec.rb",
@ -179,6 +191,7 @@ Gem::Specification.new do |s|
"spec/integration/v2/repositories_spec.rb", "spec/integration/v2/repositories_spec.rb",
"spec/integration/v2/requests_spec.rb", "spec/integration/v2/requests_spec.rb",
"spec/integration/v2/settings/env_vars_spec.rb", "spec/integration/v2/settings/env_vars_spec.rb",
"spec/integration/v2/settings/ssh_key_spec.rb",
"spec/integration/v2/users_spec.rb", "spec/integration/v2/users_spec.rb",
"spec/integration/v2_spec.backup.rb", "spec/integration/v2_spec.backup.rb",
"spec/integration/version_spec.rb", "spec/integration/version_spec.rb",
@ -194,6 +207,7 @@ Gem::Specification.new do |s|
"spec/unit/api/v2/http/build_spec.rb", "spec/unit/api/v2/http/build_spec.rb",
"spec/unit/api/v2/http/builds_spec.rb", "spec/unit/api/v2/http/builds_spec.rb",
"spec/unit/api/v2/http/caches_spec.rb", "spec/unit/api/v2/http/caches_spec.rb",
"spec/unit/api/v2/http/env_var_spec.rb",
"spec/unit/api/v2/http/hooks_spec.rb", "spec/unit/api/v2/http/hooks_spec.rb",
"spec/unit/api/v2/http/job_spec.rb", "spec/unit/api/v2/http/job_spec.rb",
"spec/unit/api/v2/http/jobs_spec.rb", "spec/unit/api/v2/http/jobs_spec.rb",
@ -219,6 +233,7 @@ Gem::Specification.new do |s|
"spec/unit/endpoint/lint_spec.rb", "spec/unit/endpoint/lint_spec.rb",
"spec/unit/endpoint/logs_spec.rb", "spec/unit/endpoint/logs_spec.rb",
"spec/unit/endpoint/repos_spec.rb", "spec/unit/endpoint/repos_spec.rb",
"spec/unit/endpoint/requests_spec.rb",
"spec/unit/endpoint/users_spec.rb", "spec/unit/endpoint/users_spec.rb",
"spec/unit/endpoint_spec.rb", "spec/unit/endpoint_spec.rb",
"spec/unit/extensions/expose_pattern_spec.rb", "spec/unit/extensions/expose_pattern_spec.rb",
@ -229,6 +244,7 @@ Gem::Specification.new do |s|
"spec/unit/helpers/json_renderer_spec.rb", "spec/unit/helpers/json_renderer_spec.rb",
"spec/unit/middleware/logging_spec.rb", "spec/unit/middleware/logging_spec.rb",
"spec/unit/middleware/scope_check_spec.rb", "spec/unit/middleware/scope_check_spec.rb",
"spec/unit/middleware/user_agent_tracker_spec.rb",
"spec/unit/responders/json_spec.rb", "spec/unit/responders/json_spec.rb",
"spec/unit/responders/service_spec.rb", "spec/unit/responders/service_spec.rb",
"tmp/.gitkeep", "tmp/.gitkeep",
@ -248,5 +264,6 @@ Gem::Specification.new do |s|
s.add_dependency 'rack-ssl', '~> 1.3', '>= 1.3.3' s.add_dependency 'rack-ssl', '~> 1.3', '>= 1.3.3'
s.add_dependency 'rack-contrib', '~> 1.1' s.add_dependency 'rack-contrib', '~> 1.1'
s.add_dependency 'memcachier' s.add_dependency 'memcachier'
s.add_dependency 'useragent'
end end