Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 168 lines (146 sloc) 4.614 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
$LOAD_PATH.unshift *Dir["#{File.dirname(__FILE__)}/vendor/**/lib"]

# stdlib
require 'net/http'
require 'net/https'
require 'net/smtp'
require 'socket'
require 'timeout'
require 'xmlrpc/client'
require 'openssl'
require 'cgi'
#~ require 'date' # This is needed by the CIA service in ruby 1.8.7 or later

# vendor
require 'mime/types'
require 'xmlsimple'
require 'activesupport'
require 'rack'
require 'sinatra'
require 'tinder'
require 'json'
require 'basecamp'
require 'tmail'
require 'xmpp4r'
require 'xmpp4r-simple'
require 'rubyforge'
require 'oauth'
require 'yammer4r'
require 'mq'

set :run, true
set :environment, :production
set :port, ARGV.first || 8080

HOSTNAME = `hostname`.chomp

begin
  require 'mongrel'
  set :server, 'mongrel'
rescue LoadError
  begin
    require 'thin'
    set :server, 'thin'
  rescue LoadError
    set :server, 'webrick'
  end
end

module GitHub
  class ServiceTimeout < Timeout::Error
  end

  # Raised when an unexpected error occurs during service hook execution.
  class ServiceError < StandardError
    attr_reader :original_exception
    def initialize(message, original_exception=nil)
      original_exception = message if message.kind_of?(Exception)
      @original_exception = original_exception
      super(message)
    end
  end

  # Raised when a service hook fails due to bad configuration. Services that
  # fail with this exception may be automatically disabled.
  class ServiceConfigurationError < ServiceError
  end

  def service(name)
    post "/#{name}/" do
      begin
        data = JSON.parse(params[:data])
        payload = parse_payload(params[:payload])
        Timeout.timeout(20, ServiceTimeout) { yield data, payload }
        status 200
        ""
      rescue GitHub::ServiceConfigurationError => boom
        status 400
        boom.message
      rescue GitHub::ServiceTimeout => boom
        status 504
        "Service Timeout"
      rescue Object => boom
        # redact sensitive info in hook_data hash
        hook_data = data || params[:data]
        hook_payload = payload || params[:payload]
        #%w[password token].each { |key| hook_data[key] &&= '<redacted>' }
        owner = hook_payload['repository']['owner']['name'] rescue nil
        repo = hook_payload['repository']['name'] rescue nil
        report_exception boom,
          :hook_name => name,
          :hook_data => hook_data.inspect,
          :hook_payload => hook_payload.inspect,
          :user => owner,
          :repo => "#{owner}/#{repo}"

        status 500
        "ERROR"
      end
    end
  end

  def parse_payload(json)
    payload = JSON.parse(json)
    payload['ref_name'] = payload['ref'].to_s.sub(/\Arefs\/(heads|tags)\//, '')
    payload
  end

  def shorten_url(url)
    Timeout::timeout(6) do
      short = Net::HTTP.get("api.bit.ly", "/shorten?version=2.0.1&longUrl=#{url}&login=github&apiKey=R_261d14760f4938f0cda9bea984b212e4")
      short = JSON.parse(short)
      short["errorCode"].zero? ? short["results"][url]["shortUrl"] : url
    end
  rescue Timeout::Error
    url
  end

  def report_exception(exception, other)

    backtrace = Array(exception.backtrace)[0..500]

    data = {
      'type' => 'exception',
      'class' => exception.class.to_s,
      'server' => HOSTNAME,
      'message' => exception.message[0..254],
      'backtrace' => backtrace.join("\n"),
      'rollup' => Digest::MD5.hexdigest(exception.class.to_s + backtrace[0])
    }

    if exception.kind_of?(GitHub::ServiceError)
      if exception.original_exception
        data['original_class'] = exception.original_exception.to_s
        data['backtrace'] = exception.original_exception.backtrace.join("\n")
        data['message'] = exception.original_exception.message[0..254]
      end
    elsif !exception.kind_of?(GitHub::ServiceTimeout)
      data['original_class'] = data['class']
      data['class'] = 'GitHub::ServiceError'
    end

    # optional
    other.each { |key, value| data[key.to_s] = value.to_s }

    if HOSTNAME == 'sh1.rs.github.com'
      # run only in github's production environment
      Net::HTTP.new('aux1', 9292).
        post('/haystack/async', "json=#{Rack::Utils.escape(data.to_json)}")
    else
      $stderr.puts data[ 'message' ]
      $stderr.puts data[ 'backtrace' ]
    end

  rescue => boom
    $stderr.puts "reporting exception failed:"
    $stderr.puts "#{boom.class}: #{boom}"
    $stderr.puts "#{boom.backtrace.join("\n")}"
    # swallow errors
  end
end
include GitHub

get "/" do
  "ok"
end

Dir["#{File.dirname(__FILE__)}/services/**/*.rb"].each { |service| load service }
Something went wrong with that request. Please try again.