forked from github/github-services
-
Notifications
You must be signed in to change notification settings - Fork 1
/
github-services.rb
159 lines (139 loc) · 4.34 KB
/
github-services.rb
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
$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 'tinder'
require 'basecamp'
require 'tmail'
require 'xmpp4r'
require 'xmpp4r-simple'
require 'rubyforge'
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)
# run only in github's production environment
return if HOSTNAME != 'sh1.rs.github.com'
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 }
Net::HTTP.new('aux1', 9292).
post('/haystack/async', "json=#{Rack::Utils.escape(data.to_json)}")
rescue => boom
$stderr.puts "reporting exception failed:"
$stderr.puts "#{boom.class}: #{boom}"
# swallow errors
end
end
include GitHub
get "/" do
"ok"
end
Dir["#{File.dirname(__FILE__)}/services/**/*.rb"].each { |service| load service }