-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathapp.rb
256 lines (227 loc) · 9.98 KB
/
app.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
$:.unshift(File.join(File.dirname(__FILE__), '/lib'))
require 'thumbs'
require 'sinatra/base'
require 'json'
class ThumbsWeb < Sinatra::Base
helpers Sinatra::GeneralHelpers
helpers Sinatra::WebhookHelpers
enable :logging
LogFile = File.join(File.dirname(__FILE__), 'log', 'unicorn.stdout.log')
get '/log' do
"<pre>#{IO.read(LogFile)}</pre>"
end
get '/tail' do
content_type :txt
stream do |out|
File.open(LogFile) do |log|
log.extend(File::Tail)
log.interval = 1
log.backward(1000)
log.tail { |line| out << line }
end
end
end
get '/' do
"OK"
end
get '/status' do
@octo_client = Octokit::Client.new(:netrc => true)
release_dir=File.expand_path(File.dirname(__FILE__))
version=release_dir.split(/\//).pop
deployed_at=File.mtime(__FILE__)
ENV.keys.each {|key| ENV.delete(key) if key =~ /(TOKEN|CLIENT_SECRET|PASS)/ }
status= {
status: "OK",
version: version,
release_dir: release_dir,
deployed_at: deployed_at,
github_user: @octo_client.login,
authenticated: @octo_client.basic_authenticated?,
rate_limit: @octo_client.ratelimit.to_h,
env: ENV.to_hash.to_yaml,
escript: ` which escript `
}
"<pre>#{status.to_yaml}</pre>"
end
get '/webhook' do
"OK"
end
post '/webhook' do
@octo_client = Octokit::Client.new(:netrc => true)
payload = JSON.parse(request.body.read)
print payload.to_yaml if ENV.key?('DEBUG')
case payload_type(payload)
when :new_pr
repo, pr = process_payload(payload)
debug_message "got repo #{repo} and pr #{pr}"
sleep 1 # github sometimes needs time
pr_worker = Thumbs::PullRequestWorker.new(:repo => repo, :pr => pr)
return "OK" unless pr_worker.open?
return "OK" if pr_worker.build_in_progress?
return "OK" unless pr_worker.thumb_config
debug_message("new pull request #{pr_worker.repo}/pulls/#{pr_worker.pr.number} ")
intro_text=<<-EOS
Thanks @#{pr_worker.pr.user.login}!
<details><Summary>Settings</Summary>
```yaml
#{pr_worker.thumb_config.to_yaml} ```
</details>
EOS
pr_worker.add_comment(intro_text) unless pr_worker.thumb_config['show_config'] == false
pr_worker.set_build_progress(:in_progress)
pr_worker.try_merge
unless pr_worker.thumb_config && pr_worker.thumb_config.key?('build_steps')
debug_message("no .thumbs config found for this repo/PR #{pr_worker.repo}##{pr_worker.pr.number}")
return "OK"
end
pr_worker.validate
pr_worker.set_build_progress(:completed)
pr_worker.create_build_status_comment
return "OK" unless pr_worker.review_count >= pr_worker.minimum_reviewers
if pr_worker.valid_for_merge?
pr_worker.create_reviewers_comment if pr_worker.review_count > 0
pr_worker.add_comment "Merging and closing this pr"
pr_worker.merge
else
debug_message("new pr #{pr_worker.repo}/pulls/#{pr_worker.pr.number} valid_for_merge? returned False")
end
when :new_comment
repo, pr = process_payload(payload)
debug_message "got repo #{repo} and pr #{pr}"
pr_worker = Thumbs::PullRequestWorker.new(:repo => repo, :pr => pr)
return "OK" unless pr_worker.open?
debug_message("new comment #{pr_worker.repo}/pulls/#{pr_worker.pr.number} #{payload['comment']['body']}")
debug_message payload['comment']['body']
if pr_worker.contains_thumbot_command?(payload['comment']['body'])
return "OK" unless pr_worker.thumb_config
if pr_worker.thumb_config['org_mode'] && pr_worker.repo_is_org?
commenting_user=payload['comment']['user']['login']
unless pr_worker.org_member?(commenting_user)
debug_message "thumb_config['org_mode']=true #{commenting_user} != org_member"
return "ERROR"
end
end
thumbot_command = pr_worker.parse_thumbot_command(payload['comment']['body'])
result=pr_worker.run_thumbot_command( thumbot_command )
status= result ? "OK" : "ERROR"
return "COMMAND:#{thumbot_command}:#{status}"
end
debug_message ""
unless pr_worker.build_progress_status == :completed
debug_message "Build not yet completed, won't do anything else"
return "OK"
end
debug_message "validate"
pr_worker.validate
if pr_worker.valid_for_merge?
review_count=pr_worker.review_count
unless review_count >= pr_worker.thumb_config['minimum_reviewers']
debug_message " #{review_count} !>= #{pr_worker.thumb_config['minimum_reviewers']}"
debug_message " reviewer rule not met "
return false
end
debug_message("new comment #{pr_worker.repo}/pulls/#{pr_worker.pr.number} valid_for_merge? OK ")
pr_worker.create_reviewers_comment
pr_worker.add_comment "Merging and closing this pr"
pr_worker.merge
else
debug_message("new comment #{pr_worker.repo}/pulls/#{pr_worker.pr.number} valid_for_merge? returned False")
end
when :code_approval
repo, pr = process_payload(payload)
debug_message "got repo #{repo} and pr #{pr}"
pr_worker = Thumbs::PullRequestWorker.new(:repo => repo, :pr => pr)
return "OK" unless pr_worker.open?
debug_message("new approval")
pr_worker.validate
if pr_worker.valid_for_merge?
review_count=pr_worker.review_count
unless review_count >= pr_worker.thumb_config['minimum_reviewers']
debug_message " #{review_count} !>= #{pr_worker.thumb_config['minimum_reviewers']}"
debug_message " reviewer rule not met "
return false
end
debug_message("code approval #{pr_worker.repo}/pulls/#{pr_worker.pr.number} valid_for_merge? OK ")
pr_worker.create_reviewers_comment
pr_worker.add_comment "Merging and closing this pr"
pr_worker.merge
else
debug_message("code approval #{pr_worker.repo}/pulls/#{pr_worker.pr.number} valid_for_merge? returned False")
end
when :new_push
debug_message "This is a #{payload_type(payload).to_s}"
repo, pr = process_payload(payload)
debug_message "got repo #{repo} and pr #{pr}"
pr_worker = Thumbs::PullRequestWorker.new(:repo => repo, :pr => pr)
return "OK" unless pr_worker.open?
debug_message("new push on pull request #{pr_worker.repo}/pulls/#{pr_worker.pr.number} ")
return "OK" if pr_worker.build_in_progress?
pr_worker.set_build_progress(:in_progress)
pr_worker.validate
pr_worker.set_build_progress(:completed)
pr_worker.create_build_status_comment
if pr_worker.valid_for_merge?
debug_message("new push #{pr_worker.repo}/pulls/#{pr_worker.pr.number} valid_for_merge? OK ")
pr_worker.merge
else
debug_message("new push #{pr_worker.repo}/pulls/#{pr_worker.pr.number} valid_for_merge? returned False")
end
when :new_base
debug_message "This is a #{payload_type(payload).to_s}"
repo, pr = process_payload(payload)
debug_message "got repo #{repo} and pr #{pr}"
pr_worker = Thumbs::PullRequestWorker.new(:repo => repo, :pr => pr)
debug_message("#{payload_type(payload).to_s} on repo #{repo}")
return "OK" if pr_worker.build_in_progress?
pr_worker.set_build_progress(:in_progress)
pr_worker.validate
pr_worker.set_build_progress(:completed)
pr_worker.create_build_status_comment
if pr_worker.valid_for_merge?
debug_message("new push #{pr_worker.repo}/pulls/#{pr_worker.pr.number} valid_for_merge? OK ")
pr_worker.merge
else
debug_message("new push #{pr_worker.repo}/pulls/#{pr_worker.pr.number} valid_for_merge? returned False")
end
when :merged_base
debug_message "This is a #{payload_type(payload).to_s}"
repo, base_ref = process_payload(payload)
debug_message "got repo #{repo} and base_ref #{base_ref}"
pull_requests_for_base_branch = @octo_client.pull_requests(repo, :state => 'open').collect { |pr| pr if pr.base.ref == base_ref }.compact
Process.detach(fork do
pull_requests_for_base_branch.each do |pr|
debug_message "Rebuild of PR: #{pr.number} with new Base ref #{base_ref}"
pr_worker=Thumbs::PullRequestWorker.new(:repo => repo, :pr => pr.number)
next unless pr_worker.thumb_config
ignore_after_n_days=90
pr_created_at=DateTime.parse(pr_worker.pr.created_at.to_s).strftime("%s").to_i
current_datetime=DateTime.now.strftime("%s").to_i
horizon_datetime=current_datetime - ( ignore_after_n_days*86400 )
if pr_created_at < horizon_datetime
debug_message "PR: #{pr.number} is too old #{pr_worker.pr.created_at} to be considered. Ignored after #{ignore_after_n_days}+ days."
next
end
if pr_worker.build_in_progress?
debug_message "PR: #{pr.number} build_in_progress : next"
next
end
pr_worker.set_build_progress(:in_progress)
pr_worker.validate
pr_worker.set_build_progress(:completed)
pr_worker.create_build_status_comment
if pr_worker.valid_for_merge?
debug_message("merged base #{pr_worker.repo}/pulls/#{pr_worker.pr.number} valid_for_merge? OK ")
pr_worker.merge
else
debug_message("merged base #{pr_worker.repo}/pulls/#{pr_worker.pr.number} valid_for_merge? returned False")
end
end
end)
when :unregistered
debug_message "#{payload.to_yaml}"
debug_message "This is not an event I recognize,: ignoring"
debug_message payload_type(payload)
end
"OK"
end
end