Skip to content

Commit

Permalink
Specs passing with newly modularized structure and config system
Browse files Browse the repository at this point in the history
  • Loading branch information
winton committed Dec 6, 2009
1 parent 8acc488 commit c5c775e
Show file tree
Hide file tree
Showing 15 changed files with 454 additions and 193 deletions.
50 changes: 50 additions & 0 deletions lib/lilypad.rb
@@ -0,0 +1,50 @@
require 'builder'
require 'net/http'
require 'rack'

lib = File.dirname(__FILE__)
require "#{lib}/lilypad/config"
require "#{lib}/lilypad/config/request"
require "#{lib}/lilypad/log"
require "#{lib}/lilypad/hoptoad/deploy"
require "#{lib}/lilypad/hoptoad/notify"
require "#{lib}/lilypad/hoptoad/xml"
require "#{lib}/rack/lilypad"

class Lilypad
class <<self

def active?
Config.api_key
end

def config(api_key=nil, &block)
if api_key
Config.api_key api_key
end
if block_given?
Config.class_eval &block
end
end

def deploy(options)
if active? && production?
Hoptoad::Deploy.new options
end
end

def notify(exception, env=nil)
if active? && production?
Hoptoad::Notify.new env, exception
end
end

def production?
Config.environments.include? ENV['RACK_ENV']
end
end
end

def Lilypad(api_key=nil, &block)
Lilypad.config api_key, &block
end
23 changes: 23 additions & 0 deletions lib/lilypad/adapters/rails.rb
@@ -0,0 +1,23 @@
class Lilypad
module Rails

def self.included(base)
ENV['RACK_ENV'] = ENV['RAILS_ENV']
base.send(:include, LilypadMethods) if Lilypad.production?
end

module LilypadMethods

private

def rescue_action_without_handler(exception)
super
Config::Request.action params[:action]
Config::Request.component params[:controller]
raise exception
end
end
end
end

ActionController::Base.send(:include, Lilypad::Rails)
10 changes: 10 additions & 0 deletions lib/lilypad/adapters/sinatra.rb
@@ -0,0 +1,10 @@
class Lilypad
module Sinatra

def self.included(base)
base.set(:raise_errors, true) if Lilypad.production?
end
end
end

Sinatra::Base.send(:include, Lilypad::Sinatra)
63 changes: 63 additions & 0 deletions lib/lilypad/config.rb
@@ -0,0 +1,63 @@
class Lilypad
class Config
class <<self

def api_key(api_key=nil, &block)
@api_key = api_key unless api_key.nil?
@api_key_block = block if block_given?
@api_key || @api_key_block
end

def deploy_url(url=nil)
@deploy_url = url unless url.nil?
@deploy_url || "http://hoptoadapp.com/deploys.txt"
end

def environments(environments=nil)
@environments = environments unless environments.nil?
@environments || %w(production staging)
end

def filters(filters=nil)
@filters = filters unless filters.nil?
@filters
end

def log(log=nil)
@log = log unless log.nil?
@log
end

def notify_url(url=nil)
@notify_url = url unless url.nil?
@url || "http://hoptoadapp.com:80/notify_url/v2/notices"
end

def rails
require "#{File.dirname(__FILE__)}/adapters/rails"
end

def reset!
self.instance_variables.each do |name|
eval "#{name} = nil"
end
end

def sinatra
require "#{File.dirname(__FILE__)}/adapters/sinatra"
end

end

module Methods

def api_key(env=nil, exception=nil)
if Config.api_key.respond_to?(:call)
Config.api_key.call env, exception
else
Config.api_key
end
end
end
end
end
24 changes: 24 additions & 0 deletions lib/lilypad/config/request.rb
@@ -0,0 +1,24 @@
class Lilypad
class Config
class Request
class <<self

def action(action=nil)
@action = action unless action.nil?
@action
end

def component(component=nil)
@component = component unless component.nil?
@component
end

def reset!
self.instance_variables.each do |name|
eval "#{name} = nil"
end
end
end
end
end
end
42 changes: 42 additions & 0 deletions lib/lilypad/hoptoad/deploy.rb
@@ -0,0 +1,42 @@
class Lilypad
class Hoptoad
class Deploy

include Config::Methods
include Log::Methods

def initialize(options)
@options = options

begin
post
rescue Exception => e
end

log :debug, @response
success?
end

private

def params
{
'api_key' => api_key,
'deploy[local_username]' => @options[:username],
'deploy[rails_env]' => @options[:environment],
'deploy[scm_revision]' => @options[:revision],
'deploy[scm_repository]' => @options[:repository]
}
end

def post
url = URI.parse Config.deploy_url
@response = Net::HTTP.post_form url, params
end

def success?
@response.class.superclass == Net::HTTPSuccess
end
end
end
end
83 changes: 83 additions & 0 deletions lib/lilypad/hoptoad/notify.rb
@@ -0,0 +1,83 @@
class Lilypad
class Hoptoad
class Notify

include Log::Methods

def initialize(env, exception)
@exception = exception
@env = env

http_start do |http|
begin
xml = XML.build *parse
http.post @uri.path, xml, headers
rescue Exception => e
end
end

if env && success?
env['hoptoad.notified'] = true
end

Config::Request.reset!
log :notify, @response
success?
end

private

def backtrace
regex = %r{^([^:]+):(\d+)(?::in `([^']+)')?$}
@exception.backtrace.map do |line|
_, file, number, method = line.match(regex).to_a
Backtrace.new file, number, method
end
end

def filter(hash)
return unless Config.filters
hash.inject({}) do |acc, (key, val)|
match = Config.filters.any? { |f| key.to_s =~ Regexp.new(f) }
acc[key] = match ? "[FILTERED]" : val
acc
end
end

def headers
{
'Content-type' => 'text/xml',
'Accept' => 'text/xml, application/xml'
}
end

def http_start(&block)
@uri = URI.parse Config.notify_url
Net::HTTP.start @uri.host, @uri.port do |http|
http.read_timeout = 5 # seconds
http.open_timeout = 2 # seconds
@response = yield http
end
end

def parse
env = filter ENV.to_hash.merge(@env || {})
if @env
request = Rack::Request.new @env
request_path = request.script_name + request.path_info
else
request = nil
request_path = 'Internal'
end
[ backtrace, env, @exception, request, request_path ]
end

def success?
@response.class.superclass == Net::HTTPSuccess
end

class Backtrace < Struct.new(:file, :number, :method)
end
end
end
end
61 changes: 61 additions & 0 deletions lib/lilypad/hoptoad/xml.rb
@@ -0,0 +1,61 @@
class Lilypad
class Hoptoad
class XML
class <<self

include Config::Methods

def build(backtrace, env, exception, request, request_path)
@@last_request = nil
xml = ::Builder::XmlMarkup.new
xml.instruct! :xml, :version => "1.0", :encoding => "UTF-8"
xml.notice :version => '2.0.0' do |n|
n.tag! 'api-key', api_key
n.notifier do |n|
n.name 'Lilypad'
n.url 'http://github.com/winton/lilypad'
n.version '0.2.4'
end
n.error do |e|
e.tag! 'class', exception.class.name
e.message exception.message
e.backtrace do |b|
backtrace.each do |line|
b.line :method => line.method, :file => line.file, :number => line.number
end
end
end
n.request do |r|
r.action Config::Request.action
r.component Config::Request.component || request_path
r.url request_path
if request && request.params.any?
r.params do |p|
request.params.each do |key, value|
p.var value.to_s, :key => key
end
end
end
if env.any?
r.tag! 'cgi-data' do |c|
env.each do |key, value|
c.var value.to_s, :key => key
end
end
end
end
n.tag! 'server-environment' do |s|
s.tag! 'project-root', Dir.pwd
s.tag! 'environment-name', ENV['RACK_ENV'] || 'development'
end
end
@@last_request = xml.target!
end

def last_request
@@last_request
end
end
end
end
end

0 comments on commit c5c775e

Please sign in to comment.