split up config.ru
This commit is contained in:
parent
fbee663505
commit
73fe04185d
11
Gemfile
11
Gemfile
|
@ -28,8 +28,19 @@ group :assets do
|
|||
gem 'guard'
|
||||
end
|
||||
|
||||
group :development, :test do
|
||||
gem 'rake', '~> 0.9.2'
|
||||
end
|
||||
|
||||
group :development do
|
||||
gem 'foreman'
|
||||
gem 'rerun'
|
||||
gem 'rb-fsevent', '~> 0.9.1'
|
||||
end
|
||||
|
||||
group :test do
|
||||
gem 'rspec', '~> 2.11'
|
||||
gem 'factory_girl', '~> 2.4.0'
|
||||
gem 'mocha', '~> 0.12'
|
||||
end
|
||||
|
||||
|
|
20
Gemfile.lock
20
Gemfile.lock
|
@ -60,7 +60,7 @@ GIT
|
|||
|
||||
GIT
|
||||
remote: git://github.com/travis-ci/travis-core.git
|
||||
revision: ddbb703d196834b7f82c6a86eff4d40b27ce588b
|
||||
revision: 60f38e45ce1d739894839ef74f405348fb5f8481
|
||||
branch: sf-travis-api
|
||||
specs:
|
||||
travis-core (0.0.1)
|
||||
|
@ -149,10 +149,13 @@ GEM
|
|||
debugger-linecache (1.1.2)
|
||||
debugger-ruby_core_source (>= 1.1.1)
|
||||
debugger-ruby_core_source (1.1.3)
|
||||
diff-lcs (1.1.3)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.0.0)
|
||||
execjs (1.4.0)
|
||||
multi_json (~> 1.0)
|
||||
factory_girl (2.4.2)
|
||||
activesupport
|
||||
faraday (0.8.4)
|
||||
multipart-post (~> 1.1)
|
||||
foreman (0.60.0)
|
||||
|
@ -173,11 +176,14 @@ GEM
|
|||
i18n (>= 0.4.0)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
metaclass (0.0.1)
|
||||
metriks (0.9.9.1)
|
||||
atomic (~> 1.0)
|
||||
avl_tree (~> 1.1.2)
|
||||
hitimes (~> 1.1)
|
||||
mime-types (1.19)
|
||||
mocha (0.12.6)
|
||||
metaclass (~> 0.0.1)
|
||||
multi_json (1.3.6)
|
||||
multipart-post (1.1.5)
|
||||
net-http-persistent (2.7)
|
||||
|
@ -221,6 +227,14 @@ GEM
|
|||
rerun (0.7.1)
|
||||
listen
|
||||
rollout (1.1.0)
|
||||
rspec (2.11.0)
|
||||
rspec-core (~> 2.11.0)
|
||||
rspec-expectations (~> 2.11.0)
|
||||
rspec-mocks (~> 2.11.0)
|
||||
rspec-core (2.11.1)
|
||||
rspec-expectations (2.11.3)
|
||||
diff-lcs (~> 1.1.3)
|
||||
rspec-mocks (2.11.3)
|
||||
sass (3.2.1)
|
||||
signature (0.1.4)
|
||||
simple_states (0.1.1)
|
||||
|
@ -265,17 +279,21 @@ DEPENDENCIES
|
|||
coffee-script
|
||||
compass
|
||||
debugger
|
||||
factory_girl (~> 2.4.0)
|
||||
foreman
|
||||
gh!
|
||||
guard
|
||||
hubble!
|
||||
mocha (~> 0.12)
|
||||
newrelic_rpm (~> 3.3.0)
|
||||
pg (~> 0.13.2)
|
||||
rack-contrib!
|
||||
rake (~> 0.9.2)
|
||||
rake-pipeline!
|
||||
rake-pipeline-web-filters!
|
||||
rb-fsevent (~> 0.9.1)
|
||||
rerun
|
||||
rspec (~> 2.11)
|
||||
sinatra
|
||||
sinatra-contrib
|
||||
tilt
|
||||
|
|
73
config.ru
73
config.ru
|
@ -1,68 +1,7 @@
|
|||
require 'travis'
|
||||
require 'travis/api/app'
|
||||
# Make sure we set that before everything
|
||||
ENV['RACK_ENV'] ||= ENV['RAILS_ENV'] || ENV['ENV']
|
||||
ENV['RAILS_ENV'] = ENV['RACK_ENV']
|
||||
|
||||
env, api_endpoint, client_endpoint, run_api, watch, deflate = ENV.values_at('RACK_ENV', 'API_ENDPOINT', 'CLIENT_ENDPOINT', 'RUN_API', 'WATCH', 'DEFLATE')
|
||||
|
||||
env ||= "development"
|
||||
api_endpoint ||= "https://api.#{Travis.config.host}" unless run_api and run_api != '0'
|
||||
run_api ||= api_endpoint.to_s.start_with? '/'
|
||||
api_endpoint ||= "/api" if run_api and run_api != '0'
|
||||
client_endpoint ||= "/"
|
||||
watch ||= false #env == "development"
|
||||
deflate ||= env == "production"
|
||||
|
||||
c = proc do |value|
|
||||
case value
|
||||
when nil, false, '0' then "\e[31m0\e[0m"
|
||||
when true, '1' then "\e[32m1\e[0m"
|
||||
else "\e[33m\"#{value}\"\e[0m"
|
||||
end
|
||||
end
|
||||
|
||||
$stderr.puts "RACK_ENV = #{c[env]}",
|
||||
"API_ENDPOINT = #{c[api_endpoint]}",
|
||||
"CLIENT_ENDPOINT = #{c[client_endpoint]}",
|
||||
"RUN_API = #{c[run_api]}",
|
||||
"WATCH = #{c[watch]}",
|
||||
"DEFLATE = #{c[deflate]}"
|
||||
|
||||
class EndpointSetter < Struct.new(:app, :endpoint)
|
||||
DEFAULT_ENDPOINT = 'https://api.travis-ci.org'
|
||||
|
||||
def call(env)
|
||||
status, headers, body = app.call(env)
|
||||
if endpoint != DEFAULT_ENDPOINT and headers.any? { |k,v| k.downcase == 'content-type' and v.start_with? 'text/html' }
|
||||
headers.delete 'Content-Length'
|
||||
body, old = [], body
|
||||
old.each { |s| body << s.gsub(DEFAULT_ENDPOINT, endpoint) }
|
||||
old.close if old.respond_to? :close
|
||||
end
|
||||
[status, headers, body]
|
||||
end
|
||||
end
|
||||
|
||||
use Rack::SSL if env == 'production'
|
||||
use Rack::Deflater if deflate and deflate != '0'
|
||||
|
||||
app = proc do |env|
|
||||
Rack::File.new(nil).tap { |f| f.path = 'public/index.html' }.serving(env)
|
||||
end
|
||||
|
||||
if run_api and run_api != '0'
|
||||
map api_endpoint.gsub(/:\d+/, '') do
|
||||
run Travis::Api::App.new
|
||||
end
|
||||
end
|
||||
|
||||
map client_endpoint do
|
||||
use EndpointSetter, api_endpoint
|
||||
|
||||
if watch and watch != '0'
|
||||
require 'rake-pipeline'
|
||||
require 'rake-pipeline/middleware'
|
||||
use Rake::Pipeline::Middleware, 'AssetFile'
|
||||
run app
|
||||
else
|
||||
run Rack::Cascade.new([Rack::File.new('public'), app])
|
||||
end
|
||||
end
|
||||
$: << 'lib'
|
||||
require 'travis/web'
|
||||
run Travis::Web::App.new
|
||||
|
|
5
lib/travis/web.rb
Normal file
5
lib/travis/web.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
module Travis
|
||||
module Web
|
||||
autoload :App, 'travis/web/app'
|
||||
end
|
||||
end
|
48
lib/travis/web/app.rb
Normal file
48
lib/travis/web/app.rb
Normal file
|
@ -0,0 +1,48 @@
|
|||
require 'rack'
|
||||
require 'rack/protection/path_traversal'
|
||||
|
||||
module Travis::Web
|
||||
class App
|
||||
autoload :Api, 'travis/web/app/api'
|
||||
autoload :Config, 'travis/web/app/config'
|
||||
autoload :Files, 'travis/web/app/files'
|
||||
autoload :Filter, 'travis/web/app/filter'
|
||||
autoload :Terminal, 'travis/web/app/terminal'
|
||||
autoload :Version, 'travis/web/app/version'
|
||||
|
||||
Rack.autoload :SSL, 'rack/ssl'
|
||||
Rack.autoload :Deflater, 'rack/deflater'
|
||||
|
||||
include Terminal
|
||||
|
||||
attr_accessor :app
|
||||
|
||||
def initialize
|
||||
config = Config.new
|
||||
announce(config)
|
||||
|
||||
@app = Rack::Builder.app do
|
||||
use Rack::SSL if config.production?
|
||||
use Rack::Protection::PathTraversal
|
||||
use Rack::Deflater if config.deflate?
|
||||
|
||||
# TODO this doesn't work, how can i extract this to a separate file/class
|
||||
# use Travis::Web::App::Api, config if config.run_api?
|
||||
if config.run_api?
|
||||
require 'travis/api/app'
|
||||
map config.api_endpoint do
|
||||
run Travis::Api::App.new
|
||||
end
|
||||
end
|
||||
|
||||
use Travis::Web::App::Version, config
|
||||
use Travis::Web::App::Filter, config
|
||||
run Travis::Web::App::Files.new
|
||||
end
|
||||
end
|
||||
|
||||
def call(env)
|
||||
app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
32
lib/travis/web/app/api.rb
Normal file
32
lib/travis/web/app/api.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
require 'travis/api/app'
|
||||
|
||||
class Travis::Web::App
|
||||
class Api
|
||||
attr_reader :app, :api, :config
|
||||
|
||||
def initialize(app, config)
|
||||
@app = app
|
||||
@api = Travis::Api::App.new
|
||||
@config = config
|
||||
end
|
||||
|
||||
def call(env)
|
||||
path = env['PATH_INFO']
|
||||
if matches?(path)
|
||||
api.call(env.merge('PATH_INFO' => api_path(path)))
|
||||
else
|
||||
app.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
def matches?(path)
|
||||
# TODO there's a redirect through /auth/post_message which doesn't have the /api
|
||||
# prefix. is that safe_redirect in travis-api? not sure how to solve this
|
||||
path.starts_with?(config.api_endpoint) || path.starts_with?('/auth')
|
||||
end
|
||||
|
||||
def api_path(path)
|
||||
path.sub(/^#{config.api_endpoint}/, '')
|
||||
end
|
||||
end
|
||||
end
|
71
lib/travis/web/app/config.rb
Normal file
71
lib/travis/web/app/config.rb
Normal file
|
@ -0,0 +1,71 @@
|
|||
class Travis::Web::App
|
||||
class Config
|
||||
OPTIONS = %w(ENV API_ENDPOINT CLIENT_ENDPOINT RUN_API WATCH DEFLATE)
|
||||
|
||||
def keys
|
||||
@keys ||= OPTIONS.map(&:downcase)
|
||||
end
|
||||
|
||||
def each
|
||||
keys.each do |key|
|
||||
yield key, send(key)
|
||||
end
|
||||
end
|
||||
|
||||
def env
|
||||
config.fetch(:env, 'development')
|
||||
end
|
||||
|
||||
def production?
|
||||
env == 'production'
|
||||
end
|
||||
|
||||
def run_api?
|
||||
!!config.fetch(:run_api, config[:api_endpoint].to_s.start_with?('/'))
|
||||
end
|
||||
|
||||
def api_endpoint
|
||||
config.fetch(:api_endpoint, run_api? ? '/api' : "https://api.travis-ci.org").gsub(/:\d+/, '')
|
||||
end
|
||||
|
||||
def client_endpoint
|
||||
config.fetch(:client_endpoint, '/')
|
||||
end
|
||||
|
||||
def deflate?
|
||||
!!config.fetch(:deflate, production?)
|
||||
end
|
||||
|
||||
def watch?
|
||||
!!config.fetch(:watch, false)
|
||||
end
|
||||
|
||||
alias run_api run_api?
|
||||
alias deflate deflate?
|
||||
alias watch watch?
|
||||
|
||||
def version
|
||||
production? ? @version ||= read_version : read_version
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def config
|
||||
@config ||= Hash[*OPTIONS.map do |key|
|
||||
[key.downcase.to_sym, cast(ENV[key])] if ENV.key?(key)
|
||||
end.compact.flatten]
|
||||
end
|
||||
|
||||
def cast(value)
|
||||
case value
|
||||
when '1', 'true' then true
|
||||
when '0', 'false' then false
|
||||
else value
|
||||
end
|
||||
end
|
||||
|
||||
def read_version
|
||||
File.read('public/version').chomp
|
||||
end
|
||||
end
|
||||
end
|
17
lib/travis/web/app/files.rb
Normal file
17
lib/travis/web/app/files.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
class Travis::Web::App
|
||||
class Files < Rack::Cascade
|
||||
def initialize
|
||||
super([public_dir, index])
|
||||
end
|
||||
|
||||
def public_dir
|
||||
Rack::File.new('public')
|
||||
end
|
||||
|
||||
def index
|
||||
proc do |env|
|
||||
Rack::File.new(nil).tap { |f| f.path = 'public/index.html' }.serving(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
34
lib/travis/web/app/filter.rb
Normal file
34
lib/travis/web/app/filter.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
class Travis::Web::App
|
||||
class Filter
|
||||
autoload :Endpoint, 'travis/web/app/filter/endpoint'
|
||||
autoload :Version, 'travis/web/app/filter/version'
|
||||
|
||||
attr_reader :app, :config, :filters
|
||||
|
||||
def initialize(app, config)
|
||||
@app = app
|
||||
@config = config
|
||||
@filters = [Endpoint.new(config), Version.new(config)]
|
||||
end
|
||||
|
||||
def call(env)
|
||||
status, headers, body = app.call(env)
|
||||
headers, body = filter(headers, body) if content_type?(headers, 'text/html')
|
||||
[status, headers, body]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def filter(headers, body)
|
||||
headers.delete 'Content-Length' # why don't we just set this to the new length?
|
||||
filtered = []
|
||||
body.each { |s| filtered << filters.inject(s) { |s, filter| filter.apply(s) } }
|
||||
body.close if body.respond_to?(:close)
|
||||
[headers, filtered]
|
||||
end
|
||||
|
||||
def content_type?(headers, type)
|
||||
headers.any? { |key, value| key.downcase == 'content-type' and value.start_with?(type) }
|
||||
end
|
||||
end
|
||||
end
|
15
lib/travis/web/app/filter/endpoint.rb
Normal file
15
lib/travis/web/app/filter/endpoint.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
class Travis::Web::App::Filter
|
||||
class Endpoint
|
||||
DEFAULT_ENDPOINT = 'https://api.travis-ci.org'
|
||||
|
||||
attr_reader :config
|
||||
|
||||
def initialize(config)
|
||||
@config = config
|
||||
end
|
||||
|
||||
def apply(string)
|
||||
string.gsub(DEFAULT_ENDPOINT, config.api_endpoint)
|
||||
end
|
||||
end
|
||||
end
|
16
lib/travis/web/app/filter/version.rb
Normal file
16
lib/travis/web/app/filter/version.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
class Travis::Web::App::Filter
|
||||
class Version
|
||||
ASSET_DIRS = %r(/(stylesheets|javascripts)/)
|
||||
|
||||
attr_reader :config
|
||||
|
||||
def initialize(config)
|
||||
@config = config
|
||||
end
|
||||
|
||||
def apply(string)
|
||||
string.gsub(ASSET_DIRS) { |match| "/#{config.version}/#{$1}/" }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
17
lib/travis/web/app/terminal.rb
Normal file
17
lib/travis/web/app/terminal.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
class Travis::Web::App
|
||||
module Terminal
|
||||
def announce(config)
|
||||
config.each do |key, value|
|
||||
$stderr.puts("#{key.upcase.rjust(15)} = #{colorize(config.send(key))}")
|
||||
end
|
||||
end
|
||||
|
||||
def colorize(value)
|
||||
case value
|
||||
when nil, false, '0' then "\e[31m0\e[0m"
|
||||
when true, '1' then "\e[32m1\e[0m"
|
||||
else "\e[33m#{value}\e[0m"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
35
lib/travis/web/app/version.rb
Normal file
35
lib/travis/web/app/version.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
class Travis::Web::App
|
||||
class Version
|
||||
attr_reader :app, :config
|
||||
|
||||
def initialize(app, config)
|
||||
@app = app
|
||||
@config = config
|
||||
end
|
||||
|
||||
def call(env)
|
||||
path = env['PATH_INFO']
|
||||
if pass?(path)
|
||||
app.call(env)
|
||||
elsif versioned?(path)
|
||||
app.call(env.merge('PATH_INFO' => strip_version(path)))
|
||||
else
|
||||
[404, { 'Content-Type' => 'text/html', 'Content-Length' => '9' }, ['not found']]
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def pass?(path)
|
||||
['/', '/index.html', 'current'].include?(path)
|
||||
end
|
||||
|
||||
def versioned?(path)
|
||||
path.starts_with?("/#{config.version}/")
|
||||
end
|
||||
|
||||
def strip_version(path)
|
||||
path.sub(%r(/#{config.version}/), '')
|
||||
end
|
||||
end
|
||||
end
|
1
public/version
Normal file
1
public/version
Normal file
|
@ -0,0 +1 @@
|
|||
1
|
113
spec/app/config_spec.rb
Normal file
113
spec/app/config_spec.rb
Normal file
|
@ -0,0 +1,113 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Travis::Web::App::Config do
|
||||
let(:config) { Travis::Web::App::Config.new }
|
||||
|
||||
before :each do
|
||||
@env = ENV.clone
|
||||
ENV.clear
|
||||
end
|
||||
|
||||
after :each do
|
||||
ENV.replace(@env)
|
||||
end
|
||||
|
||||
describe 'env' do
|
||||
it 'given ENV=foo it returns foo' do
|
||||
ENV['ENV'] = 'foo'
|
||||
config.env.should == 'foo'
|
||||
end
|
||||
|
||||
it 'defaults to development' do
|
||||
config.env.should == 'development'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'run_api?' do
|
||||
it 'given RUN_API=1 it returns true' do
|
||||
ENV['RUN_API'] = '1'
|
||||
config.run_api?.should be_true
|
||||
end
|
||||
|
||||
it 'given RUN_API=0 it returns false' do
|
||||
ENV['RUN_API'] = '0'
|
||||
config.run_api?.should be_false
|
||||
end
|
||||
|
||||
it 'defaults to true if api_endpoint is local' do
|
||||
ENV['API_ENDPOINT'] = '/api'
|
||||
config.run_api?.should be_true
|
||||
end
|
||||
|
||||
it 'defaults to false if api_endpoint is not local' do
|
||||
ENV['API_ENDPOINT'] = 'https://api.travis-ci.com'
|
||||
config.run_api?.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe 'api_endpoint' do
|
||||
it 'given API_ENDPOINT=https://api.travis-ci.com it returns the given url' do
|
||||
ENV['API_ENDPOINT'] = 'https://api.travis-ci.com'
|
||||
config.api_endpoint.should == 'https://api.travis-ci.com'
|
||||
end
|
||||
|
||||
it 'defaults to /api if run_api? is true' do
|
||||
config.stubs(:run_api?).returns(true)
|
||||
config.api_endpoint.should == '/api'
|
||||
end
|
||||
|
||||
it 'defaults to https://api.travis-ci.org if run_api? is false' do
|
||||
config.stubs(:run_api?).returns(false)
|
||||
config.api_endpoint.should == 'https://api.travis-ci.org'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'client_endpoint' do
|
||||
it 'given CLIENT_ENDPOINT=/client it returns the given url' do
|
||||
ENV['CLIENT_ENDPOINT'] = '/client'
|
||||
config.client_endpoint.should == '/client'
|
||||
end
|
||||
|
||||
it 'defaults to /' do
|
||||
config.client_endpoint.should == '/'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'deflate?' do
|
||||
it 'given DEFLATE=1 it returns true' do
|
||||
ENV['DEFLATE'] = '1'
|
||||
config.deflate.should be_true
|
||||
end
|
||||
|
||||
it 'given DEFLATE=0 it returns false' do
|
||||
ENV['DEFLATE'] = '0'
|
||||
config.deflate.should be_false
|
||||
end
|
||||
|
||||
it 'defaults to true if env is production' do
|
||||
config.stubs(:env).returns('production')
|
||||
config.deflate.should be_true
|
||||
end
|
||||
|
||||
it 'defaults to false if env is not production' do
|
||||
config.stubs(:env).returns('development')
|
||||
config.deflate.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe 'watch?' do
|
||||
it 'given WATCH=1 it returns true' do
|
||||
ENV['WATCH'] = '1'
|
||||
config.watch?.should be_true
|
||||
end
|
||||
|
||||
it 'given WATCH=0 it returns false' do
|
||||
ENV['WATCH'] = '0'
|
||||
config.watch?.should be_false
|
||||
end
|
||||
|
||||
it 'defaults to false' do
|
||||
config.watch?.should be_false
|
||||
end
|
||||
end
|
||||
end
|
19
spec/spec_helper.rb
Normal file
19
spec/spec_helper.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
# ENV['RACK_ENV'] = ENV['RAILS_ENV'] = ENV['ENV'] = 'test'
|
||||
|
||||
require 'rspec'
|
||||
require 'travis/web'
|
||||
require 'sinatra/test_helpers'
|
||||
|
||||
# require 'logger'
|
||||
# require 'gh'
|
||||
# require 'multi_json'
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.mock_framework = :mocha
|
||||
config.expect_with :rspec, :stdlib
|
||||
# config.include TestHelpers
|
||||
|
||||
# config.before :each do
|
||||
# set_app Travis::Web::App.new
|
||||
# end
|
||||
end
|
Loading…
Reference in New Issue
Block a user