hookworm-handlers 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/.rubocop.yml +3 -0
- data/.simplecov +6 -0
- data/.travis.yml +17 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/LICENSE.md +23 -0
- data/README.md +29 -0
- data/Rakefile +20 -0
- data/bin/hookworm-annotator +6 -0
- data/bin/hookworm-build-index-handler +6 -0
- data/bin/hookworm-logging-handler +6 -0
- data/bin/hookworm-rogue-commit-handler +6 -0
- data/hookworm-handlers.gemspec +32 -0
- data/lib/hookworm/annotator.rb +49 -0
- data/lib/hookworm/build_index_handler.rb +132 -0
- data/lib/hookworm/github_payload_annotator.rb +110 -0
- data/lib/hookworm/handlers/version.rb +5 -0
- data/lib/hookworm/handlers.rb +5 -0
- data/lib/hookworm/logging_handler.rb +55 -0
- data/lib/hookworm/rogue-commit-email-tmpl.erb +153 -0
- data/lib/hookworm/rogue_commit_handler.rb +240 -0
- data/lib/hookworm/travis_payload_annotator.rb +23 -0
- data/lib/hookworm-handlers.rb +7 -0
- data/sampledata/github-payloads/bogus.json +4 -0
- data/sampledata/github-payloads/branch_delete.json +41 -0
- data/sampledata/github-payloads/pull_request.json +153 -0
- data/sampledata/github-payloads/rogue.json +152 -0
- data/sampledata/github-payloads/rogue_unwatched_branch.json +152 -0
- data/sampledata/github-payloads/rogue_unwatched_path.json +91 -0
- data/sampledata/github-payloads/valid.json +66 -0
- data/sampledata/github-payloads/with_nulls.json +67 -0
- data/sampledata/travis-payloads/annotated_success.json +76 -0
- data/sampledata/travis-payloads/success.json +74 -0
- data/sampledata/travis-payloads/valid.json +56 -0
- data/spec/lib/hookworm/annotator_spec.rb +103 -0
- data/spec/lib/hookworm/build_index_handler_spec.rb +110 -0
- data/spec/lib/hookworm/logging_handler_spec.rb +134 -0
- data/spec/lib/hookworm/rogue_commit_handler_spec.rb +65 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support.rb +117 -0
- metadata +222 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
From: <%= @from %>
|
2
|
+
To: <%= @recipients %>
|
3
|
+
Subject: [hookworm] Rogue commit by <%= @head_commit_author %> to <%= @repo %> <%= @ref %> (<%= @head_commit_id %>)
|
4
|
+
Date: <%= @date %>
|
5
|
+
Message-ID: <<%= @message_id %>@<%= @hostname %>>
|
6
|
+
List-ID: <%= @repo %> <hookworm.github.com>
|
7
|
+
Content-Type: multipart/alternative;
|
8
|
+
boundary="--==ZOMGBOUNDARAAAYYYYY";
|
9
|
+
charset=UTF-8
|
10
|
+
Content-Transfer-Encoding: 7bit
|
11
|
+
|
12
|
+
----==ZOMGBOUNDARAAAYYYYY
|
13
|
+
Date: <%= @date %>
|
14
|
+
Mime-Version: 1.0
|
15
|
+
Content-Type: text/plain; charset=utf8
|
16
|
+
Content-Transfer-Encoding: 7bit
|
17
|
+
|
18
|
+
Rogue commit detected!
|
19
|
+
|
20
|
+
Repo <%= @repo %>
|
21
|
+
Ref <%= @ref %>
|
22
|
+
ID <%= @head_commit_id %>
|
23
|
+
Author <%= @head_commit_author %>
|
24
|
+
Committer <%= @head_commit_committer %>
|
25
|
+
Timestamp <%= @head_commit_timestamp %>
|
26
|
+
Message <%= @head_commit_message_text %>
|
27
|
+
|
28
|
+
--
|
29
|
+
This email was sent by hookworm: https://github.com/modcloth-labs/hookworm
|
30
|
+
|
31
|
+
A rogue commit is a commit made directly to a branch that is being watched such
|
32
|
+
that only pull requests should be merged into them.
|
33
|
+
|
34
|
+
The configured watched branches are:
|
35
|
+
|
36
|
+
<% (@watched_branches || []).each do |branch| %> - <%= branch %>
|
37
|
+
<% end %>
|
38
|
+
|
39
|
+
The configured watched paths are:
|
40
|
+
|
41
|
+
<% (@watched_paths || []).each do |path| %> - <%= path %>
|
42
|
+
<% end %>
|
43
|
+
|
44
|
+
|
45
|
+
If you believe this rogue commit email is an error, you should hunt down the
|
46
|
+
party responsible for the hookworm instance registered as a WebHook URL in this
|
47
|
+
repo's service hook settings (<%= @repo_url %>/settings/hooks).
|
48
|
+
|
49
|
+
Pretty please submit issues specific to hookworm functionality on github:
|
50
|
+
https://github.com/modcloth-labs/hookworm/issues/new
|
51
|
+
|
52
|
+
----==ZOMGBOUNDARAAAYYYYY
|
53
|
+
Date: <%= @date %>
|
54
|
+
Mime-Version: 1.0
|
55
|
+
Content-Type: text/html; charset=utf8
|
56
|
+
Content-Transfer-Encoding: 7bit
|
57
|
+
|
58
|
+
<div>
|
59
|
+
<h1><a href="<%= @head_commit_url %>">Rogue commit detected!</a></h1>
|
60
|
+
|
61
|
+
<table>
|
62
|
+
<thead><th></th><th></th></thead>
|
63
|
+
<tbody>
|
64
|
+
<tr>
|
65
|
+
<td style="text-align:right;vertical-align:top;">
|
66
|
+
<strong>Repo</strong>:
|
67
|
+
</td>
|
68
|
+
<td><%= @repo %></td>
|
69
|
+
</tr>
|
70
|
+
<tr>
|
71
|
+
<td style="text-align:right;vertical-align:top;">
|
72
|
+
<strong>Ref</strong>:
|
73
|
+
</td>
|
74
|
+
<td><%= @ref %></td>
|
75
|
+
</tr>
|
76
|
+
<tr>
|
77
|
+
<td style="text-align:right;vertical-align:top;">
|
78
|
+
<strong>ID</strong>:
|
79
|
+
</td>
|
80
|
+
<td><a href="<%= @head_commit_url %>"><%= @head_commit_id %></a></td>
|
81
|
+
</tr>
|
82
|
+
<tr>
|
83
|
+
<td style="text-align:right;vertical-align:top;">
|
84
|
+
<strong>Author</strong>:
|
85
|
+
</td>
|
86
|
+
<td><%= @head_commit_author %></td>
|
87
|
+
</tr>
|
88
|
+
<tr>
|
89
|
+
<td style="text-align:right;vertical-align:top;">
|
90
|
+
<strong>Committer</strong>:
|
91
|
+
</td>
|
92
|
+
<td><%= @head_commit_committer %></td>
|
93
|
+
</tr>
|
94
|
+
<tr>
|
95
|
+
<td style="text-align:right;vertical-align:top;">
|
96
|
+
<strong>Timestamp</strong>:
|
97
|
+
</td>
|
98
|
+
<td><%= @head_commit_timestamp %></td>
|
99
|
+
</tr>
|
100
|
+
<tr>
|
101
|
+
<td style="text-align:right;vertical-align:top;">
|
102
|
+
<strong>Message</strong>:
|
103
|
+
</td>
|
104
|
+
<td><%= @head_commit_message_html %></td>
|
105
|
+
</tr>
|
106
|
+
</tbody>
|
107
|
+
</table>
|
108
|
+
</div>
|
109
|
+
|
110
|
+
<hr/>
|
111
|
+
<div style="font-size:.8em">
|
112
|
+
<p>
|
113
|
+
This email was sent by
|
114
|
+
<a href="https://github.com/modcloth-labs/hookworm">hookworm</a>.
|
115
|
+
</p>
|
116
|
+
|
117
|
+
<p>
|
118
|
+
A rogue commit is a commit made directly to a branch that is being watched such
|
119
|
+
that only pull requests should be merged into them.
|
120
|
+
</p>
|
121
|
+
|
122
|
+
<p>
|
123
|
+
The configured watched branches are:
|
124
|
+
</p>
|
125
|
+
|
126
|
+
<ul>
|
127
|
+
<% (@watched_branches || []).each do |branch| %><li><strong><%= branch %></strong></li>
|
128
|
+
<% end %>
|
129
|
+
</ul>
|
130
|
+
|
131
|
+
<p>
|
132
|
+
The configured watched paths are:
|
133
|
+
</p>
|
134
|
+
|
135
|
+
<ul>
|
136
|
+
<% (@watched_paths || []).each do |path| %><li><strong><%= path %></strong></li>
|
137
|
+
<% end %>
|
138
|
+
</ul>
|
139
|
+
|
140
|
+
<p>
|
141
|
+
If you believe this rogue commit email is an error, you should hunt down the
|
142
|
+
party responsible for the hookworm instance registered as a WebHook URL in
|
143
|
+
this repo's <a href="<%= @repo_url %>/settings/hooks">service hook settings</a>.
|
144
|
+
</p>
|
145
|
+
|
146
|
+
<p>
|
147
|
+
Pretty please submit issues specific to hookworm functionality
|
148
|
+
<a href="https://github.com/modcloth-labs/hookworm/issues/new">on github</a>
|
149
|
+
</p>
|
150
|
+
|
151
|
+
</div>
|
152
|
+
|
153
|
+
----==ZOMGBOUNDARAAAYYYYY--
|
@@ -0,0 +1,240 @@
|
|
1
|
+
# vim:fileencoding=utf-8
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
require 'json'
|
5
|
+
require 'net/smtp'
|
6
|
+
require 'time'
|
7
|
+
require 'uri'
|
8
|
+
require 'hookworm-base'
|
9
|
+
require 'hookworm/emailer'
|
10
|
+
|
11
|
+
module Hookworm
|
12
|
+
# # Hookworm Rogue Commit Handler
|
13
|
+
#
|
14
|
+
# The rogue commit handler is specific to GitHub payloads. It will inspect a
|
15
|
+
# payload in the context of the given `watched_branches` and `watched_paths`
|
16
|
+
# and send a "rogue commit email" to the email recipients given in
|
17
|
+
# `email_recipients` to provide visibility roughly equivalent to those
|
18
|
+
# commits that result from pull request merges.
|
19
|
+
#
|
20
|
+
# Because the rogue commit handler is affected by so many arguments, here
|
21
|
+
# they are again with more details about their associated behavior:
|
22
|
+
#
|
23
|
+
# ## `watched_branches`
|
24
|
+
# The `watched_branches` argument should be a comma-delimited list of regular
|
25
|
+
# expressions, e.g.: `watched_branches='^master$,^release_[0-9]'`. If a
|
26
|
+
# commit payload is received that was not the result of a pull request merge
|
27
|
+
# and the Hookworm Annotator handler has determined that the branch name
|
28
|
+
# matches any of the entries in `watched_branches`, then a rogue commit email
|
29
|
+
# will be sent.
|
30
|
+
#
|
31
|
+
# ## `watched_paths`
|
32
|
+
# The `watched_paths` argument should be a comma-delimited list of regular
|
33
|
+
# expressions, e.g.: `watched_paths='.*\.(go|rb|py)$,bin/.*'`. If a commit
|
34
|
+
# payload is received that was not the result of a pull request merge and the
|
35
|
+
# Hookworm Annotator handler has determined that one of the commits in the
|
36
|
+
# payload contains a path matching any of the entries in `watched_paths`,
|
37
|
+
# then a rogue commit email will be sent.
|
38
|
+
#
|
39
|
+
# ## `email_from_addr`
|
40
|
+
# The `email_from_addr` is the email address used as the `From` header and
|
41
|
+
# SMTP MAIL address when sending rogue commit emails, e.g.:
|
42
|
+
# `email_from_addr='hookworm-noreply@company.example.com'`.
|
43
|
+
#
|
44
|
+
# ## `email_recipients`
|
45
|
+
# The `email_recipients` argument should be a comma-delimited list of email
|
46
|
+
# addresses (without display name) used in the `To` header and SMTP RCPT
|
47
|
+
# addresses when sending rogue commit emails, e.g.:
|
48
|
+
# `email_recipients='devs@example.com,proj+hookworm@partner.example.net'`
|
49
|
+
#
|
50
|
+
# ## `email_uri`
|
51
|
+
# The `email_uri` argument should be a well-formed URI containing the SMTP
|
52
|
+
# hostname and port and potentially the username and password used for plain
|
53
|
+
# SMTP auth, e.g.:
|
54
|
+
# `email_uri='smtp://hookworm:secret@mailhost.example.com:1587'`
|
55
|
+
class RogueCommitHandler
|
56
|
+
include Hookworm::Base
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def handle_github
|
61
|
+
payload = JSON.parse(input_stream.read, symbolize_names: true)
|
62
|
+
begin
|
63
|
+
Judger.new(cfg).judge_payload(payload)
|
64
|
+
rescue StandardError
|
65
|
+
return 1
|
66
|
+
ensure
|
67
|
+
output_stream.puts JSON.pretty_generate(payload)
|
68
|
+
end
|
69
|
+
0
|
70
|
+
end
|
71
|
+
|
72
|
+
def handle_travis
|
73
|
+
78
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class Judger
|
78
|
+
attr_reader :cfg
|
79
|
+
|
80
|
+
def initialize(cfg)
|
81
|
+
@cfg = cfg
|
82
|
+
end
|
83
|
+
|
84
|
+
def judge_payload(payload)
|
85
|
+
return unless watched_branch?(payload)
|
86
|
+
hcid = payload[:head_commit][:id]
|
87
|
+
return if pr_merge?(payload, hcid)
|
88
|
+
return unless watched_path?(payload, hcid)
|
89
|
+
safe_send_rogue_commit_email!(payload)
|
90
|
+
end
|
91
|
+
|
92
|
+
def new_judge_payload(payload)
|
93
|
+
return unless watched_branch?(payload)
|
94
|
+
hcid = payload[:head_commit][:id]
|
95
|
+
return if pr_merge?(payload, hcid)
|
96
|
+
return unless watched_path?(payload, hcid)
|
97
|
+
safe_send_rogue_commit_email!(payload)
|
98
|
+
end
|
99
|
+
|
100
|
+
def watched_branch?(payload)
|
101
|
+
unless payload[:is_watched_branch]
|
102
|
+
log.debug { "#{payload[:ref]} is not a watched branch, yay!" }
|
103
|
+
return false
|
104
|
+
end
|
105
|
+
|
106
|
+
log.debug { "#{payload[:ref]} is a watched branch!" }
|
107
|
+
true
|
108
|
+
end
|
109
|
+
|
110
|
+
def pr_merge?(payload, hcid)
|
111
|
+
if payload[:is_pr_merge]
|
112
|
+
log.info { "#{hcid} is a pull request merge, yay!" }
|
113
|
+
return true
|
114
|
+
end
|
115
|
+
|
116
|
+
log.debug { "#{hcid} is not a pull request merge!" }
|
117
|
+
false
|
118
|
+
end
|
119
|
+
|
120
|
+
def watched_path?(payload, hcid)
|
121
|
+
unless payload[:has_watched_path]
|
122
|
+
log.debug { "#{hcid} does not contain watched paths, yay!" }
|
123
|
+
return false
|
124
|
+
end
|
125
|
+
|
126
|
+
log.debug { "#{hcid} contains watched paths!" }
|
127
|
+
true
|
128
|
+
end
|
129
|
+
|
130
|
+
def safe_send_rogue_commit_email!(payload)
|
131
|
+
send_rogue_commit_email!(payload)
|
132
|
+
log.debug { "Sent rogue commit email to #{recipients}" }
|
133
|
+
rescue => e
|
134
|
+
log.error { "#{e.class.name} #{e.message}" }
|
135
|
+
log.debug { e.backtrace.join("\n") }
|
136
|
+
raise e
|
137
|
+
end
|
138
|
+
|
139
|
+
def send_rogue_commit_email!(payload)
|
140
|
+
log_rogue_commit(payload)
|
141
|
+
|
142
|
+
if recipients.empty?
|
143
|
+
log.warn { 'No email recipients specified, so no emailing!' }
|
144
|
+
return
|
145
|
+
end
|
146
|
+
|
147
|
+
email_body = render_email(payload)
|
148
|
+
log.debug { "Email message:\n#{email_body}" }
|
149
|
+
|
150
|
+
emailer.send(fromaddr, recipients, email_body)
|
151
|
+
end
|
152
|
+
|
153
|
+
def render_email(payload)
|
154
|
+
EmailRenderContext.new(self, payload, rogue_commit_email_tmpl).render
|
155
|
+
end
|
156
|
+
|
157
|
+
def rogue_commit_email_tmpl
|
158
|
+
ERB.new(rogue_commit_email_tmpl_string)
|
159
|
+
end
|
160
|
+
|
161
|
+
def rogue_commit_email_tmpl_string
|
162
|
+
File.read(File.expand_path('../rogue-commit-email-tmpl.erb', __FILE__))
|
163
|
+
end
|
164
|
+
|
165
|
+
def recipients
|
166
|
+
@recipients ||= (cfg[:worm_flags][:email_recipients] || '').commasplit
|
167
|
+
end
|
168
|
+
|
169
|
+
def fromaddr
|
170
|
+
@fromaddr ||= cfg[:worm_flags][:email_from_addr]
|
171
|
+
end
|
172
|
+
|
173
|
+
def watched_branches
|
174
|
+
@watched_branches ||= (
|
175
|
+
cfg[:worm_flags][:watched_branches] || ''
|
176
|
+
).commasplit
|
177
|
+
end
|
178
|
+
|
179
|
+
def watched_paths
|
180
|
+
@watched_paths ||= (cfg[:worm_flags][:watched_paths] || '').commasplit
|
181
|
+
end
|
182
|
+
|
183
|
+
def emailer
|
184
|
+
@emailer ||= Hookworm::Emailer.new(cfg[:worm_flags][:email_uri])
|
185
|
+
end
|
186
|
+
|
187
|
+
def log_rogue_commit(payload)
|
188
|
+
log.warn do
|
189
|
+
"WARNING rogue commit! #{payload}, " <<
|
190
|
+
"head commit: #{payload[:head_commit]}"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def log
|
195
|
+
@log ||= Logger.new($stderr)
|
196
|
+
end
|
197
|
+
|
198
|
+
class EmailRenderContext
|
199
|
+
def initialize(judger, payload, tmpl)
|
200
|
+
assign_judger_vars(judger)
|
201
|
+
assign_payload_vars(payload)
|
202
|
+
@tmpl = tmpl
|
203
|
+
@date = Time.now.utc.rfc2822
|
204
|
+
@message_id = Time.now.strftime('%s%9N')
|
205
|
+
@hostname = Socket.gethostname
|
206
|
+
assign_head_commit_vars(payload[:head_commit])
|
207
|
+
end
|
208
|
+
|
209
|
+
def assign_judger_vars(judger)
|
210
|
+
@cfg = judger.cfg
|
211
|
+
@from = judger.fromaddr
|
212
|
+
@recipients = judger.recipients.join(', ')
|
213
|
+
@watched_branches = judger.watched_branches
|
214
|
+
@watched_paths = judger.watched_paths
|
215
|
+
end
|
216
|
+
|
217
|
+
def assign_payload_vars(payload)
|
218
|
+
@payload = payload
|
219
|
+
@repo = "#{payload[:repository][:owner][:name]}/" <<
|
220
|
+
"#{payload[:repository][:name]}"
|
221
|
+
@ref = payload[:ref]
|
222
|
+
@repo_url = payload[:repository][:url]
|
223
|
+
end
|
224
|
+
|
225
|
+
def assign_head_commit_vars(hc)
|
226
|
+
@head_commit_id = hc[:id]
|
227
|
+
@head_commit_url = hc[:url]
|
228
|
+
@head_commit_author = hc[:author][:name]
|
229
|
+
@head_commit_committer = hc[:committer][:name]
|
230
|
+
@head_commit_message_text = hc[:message].to_plaintext
|
231
|
+
@head_commit_message_html = hc[:message].to_html
|
232
|
+
@head_commit_timestamp = hc[:timestamp]
|
233
|
+
end
|
234
|
+
|
235
|
+
def render
|
236
|
+
@tmpl.result(binding)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Hookworm
|
2
|
+
class TravisPayloadAnnotator
|
3
|
+
def annotate(payload)
|
4
|
+
annotated = payload.clone
|
5
|
+
add_repo_slug!(annotated)
|
6
|
+
annotated[:success] = success?(payload)
|
7
|
+
annotated
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def add_repo_slug!(payload)
|
13
|
+
repo = (payload[:repository] || {})
|
14
|
+
if repo[:owner_name] && repo[:name]
|
15
|
+
repo[:slug] = "#{repo[:owner_name]}/#{repo[:name]}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def success?(payload)
|
20
|
+
payload[:result] == 0 && payload[:result_message].downcase == 'passed'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module Hookworm
|
2
|
+
autoload :Annotator, 'hookworm/annotator'
|
3
|
+
autoload :BuildIndexHandler, 'hookworm/build_index_handler'
|
4
|
+
autoload :Handlers, 'hookworm/handlers'
|
5
|
+
autoload :LoggingHandler, 'hookworm/logging_handler'
|
6
|
+
autoload :RogueCommitHandler, 'hookworm/rogue_commit_handler'
|
7
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
{
|
2
|
+
"ref": "refs/heads/ensuring-watched-branches-and-paths-are-quote-free",
|
3
|
+
"after": "0000000000000000000000000000000000000000",
|
4
|
+
"before": "a1fcfc8fe4017bccb4f156ac5a786c08a6968517",
|
5
|
+
"created": false,
|
6
|
+
"deleted": true,
|
7
|
+
"forced": true,
|
8
|
+
"compare": "https://github.com/modcloth-labs/hookworm/compare/a1fcfc8fe401...000000000000",
|
9
|
+
"commits": [],
|
10
|
+
"head_commit": null,
|
11
|
+
"repository": {
|
12
|
+
"id": 10417548,
|
13
|
+
"name": "hookworm",
|
14
|
+
"url": "https://github.com/modcloth-labs/hookworm",
|
15
|
+
"description": "GitHub & Travis hook receiving thingydoo",
|
16
|
+
"homepage": "",
|
17
|
+
"watchers": 2,
|
18
|
+
"stargazers": 2,
|
19
|
+
"forks": 2,
|
20
|
+
"fork": false,
|
21
|
+
"size": 612,
|
22
|
+
"owner": {
|
23
|
+
"name": "modcloth-labs",
|
24
|
+
"email": "labs@modcloth.com"
|
25
|
+
},
|
26
|
+
"private": false,
|
27
|
+
"open_issues": 0,
|
28
|
+
"has_issues": true,
|
29
|
+
"has_downloads": true,
|
30
|
+
"has_wiki": true,
|
31
|
+
"language": "Ruby",
|
32
|
+
"created_at": 1370060266,
|
33
|
+
"pushed_at": 1378653604,
|
34
|
+
"master_branch": "master",
|
35
|
+
"organization": "modcloth-labs"
|
36
|
+
},
|
37
|
+
"pusher": {
|
38
|
+
"name": "meatballhat",
|
39
|
+
"email": "dan@meatballhat.com"
|
40
|
+
}
|
41
|
+
}
|
@@ -0,0 +1,153 @@
|
|
1
|
+
{
|
2
|
+
"ref": "refs/heads/master",
|
3
|
+
"after": "d0afb08e931361f179a7e0fd29daec7ca1663233",
|
4
|
+
"before": "926ed297f149354424c1968924bf944c5b69a7ec",
|
5
|
+
"created": false,
|
6
|
+
"deleted": false,
|
7
|
+
"forced": false,
|
8
|
+
"compare": "https://github.com/modcloth-labs/hookworm/compare/926ed297f149...d0afb08e9313",
|
9
|
+
"commits": [
|
10
|
+
{
|
11
|
+
"id": "7afdcae33a1903e52d0290e738b868d944ce3f60",
|
12
|
+
"distinct": true,
|
13
|
+
"message": "Merge pull request #1 from modcloth-labs/payload-parsing-and-emailing\n\nPayload parsing and emaœling",
|
14
|
+
"timestamp": "2013-06-01T19:28:39-07:00",
|
15
|
+
"url": "https://github.com/modcloth-labs/hookworm/commit/7afdcae33a1903e52d0290e738b868d944ce3f60",
|
16
|
+
"author": {
|
17
|
+
"name": "Dan Buch",
|
18
|
+
"email": "daniel.buch@gmail.com",
|
19
|
+
"username": "meatballhat"
|
20
|
+
},
|
21
|
+
"committer": {
|
22
|
+
"name": "Dan Buch",
|
23
|
+
"email": "daniel.buch@gmail.com",
|
24
|
+
"username": "meatballhat"
|
25
|
+
},
|
26
|
+
"added": [
|
27
|
+
"emailer.go",
|
28
|
+
"example-payload.json",
|
29
|
+
"payload.go"
|
30
|
+
],
|
31
|
+
"removed": [
|
32
|
+
|
33
|
+
],
|
34
|
+
"modified": [
|
35
|
+
"Makefile",
|
36
|
+
"server.go"
|
37
|
+
]
|
38
|
+
},
|
39
|
+
{
|
40
|
+
"id": "323fa5bebc49cbeac869a242682a56c83d4566cc",
|
41
|
+
"distinct": true,
|
42
|
+
"message": "Handling JSON nulls all over the place\n\nwhich I may end up reverting in favor of the {}interface + type\nassertion approach.",
|
43
|
+
"timestamp": "2013-06-02T09:42:59-07:00",
|
44
|
+
"url": "https://github.com/modcloth-labs/hookworm/commit/323fa5bebc49cbeac869a242682a56c83d4566cc",
|
45
|
+
"author": {
|
46
|
+
"name": "Dan Buch",
|
47
|
+
"email": "d.buch@modcloth.com",
|
48
|
+
"username": "meatballhat"
|
49
|
+
},
|
50
|
+
"committer": {
|
51
|
+
"name": "Dan Buch",
|
52
|
+
"email": "d.buch@modcloth.com",
|
53
|
+
"username": "meatballhat"
|
54
|
+
},
|
55
|
+
"added": [
|
56
|
+
"sampledata/payload-with-nulls.json",
|
57
|
+
"sampledata/payload.json"
|
58
|
+
],
|
59
|
+
"removed": [
|
60
|
+
"example-payload.json"
|
61
|
+
],
|
62
|
+
"modified": [
|
63
|
+
"payload.go",
|
64
|
+
"server.go"
|
65
|
+
]
|
66
|
+
},
|
67
|
+
{
|
68
|
+
"id": "d0afb08e931361f179a7e0fd29daec7ca1663233",
|
69
|
+
"distinct": true,
|
70
|
+
"message": "Merge pull request #2 from modcloth-labs/payload-parsing-and-emailing\n\nHandling JSON nulls all over the place",
|
71
|
+
"timestamp": "2013-06-02T09:47:08-07:00",
|
72
|
+
"url": "https://github.com/modcloth-labs/hookworm/commit/d0afb08e931361f179a7e0fd29daec7ca1663233",
|
73
|
+
"author": {
|
74
|
+
"name": "Dan Buch",
|
75
|
+
"email": "daniel.buch@gmail.com",
|
76
|
+
"username": "meatballhat"
|
77
|
+
},
|
78
|
+
"committer": {
|
79
|
+
"name": "Dan Buch",
|
80
|
+
"email": "daniel.buch@gmail.com",
|
81
|
+
"username": "meatballhat"
|
82
|
+
},
|
83
|
+
"added": [
|
84
|
+
"sampledata/payload-with-nulls.json",
|
85
|
+
"sampledata/payload.json"
|
86
|
+
],
|
87
|
+
"removed": [
|
88
|
+
"example-payload.json"
|
89
|
+
],
|
90
|
+
"modified": [
|
91
|
+
"payload.go",
|
92
|
+
"server.go"
|
93
|
+
]
|
94
|
+
}
|
95
|
+
],
|
96
|
+
"head_commit": {
|
97
|
+
"id": "d0afb08e931361f179a7e0fd29daec7ca1663233",
|
98
|
+
"distinct": true,
|
99
|
+
"message": "Merge pull request #2 from modcloth-labs/payload-parsing-and-emailing\n\nHandling JSON nulls all over the place",
|
100
|
+
"timestamp": "2013-06-02T09:47:08-07:00",
|
101
|
+
"url": "https://github.com/modcloth-labs/hookworm/commit/d0afb08e931361f179a7e0fd29daec7ca1663233",
|
102
|
+
"author": {
|
103
|
+
"name": "Dan Buch",
|
104
|
+
"email": "daniel.buch@gmail.com",
|
105
|
+
"username": "meatballhat"
|
106
|
+
},
|
107
|
+
"committer": {
|
108
|
+
"name": "Dan Buch",
|
109
|
+
"email": "daniel.buch@gmail.com",
|
110
|
+
"username": "meatballhat"
|
111
|
+
},
|
112
|
+
"added": [
|
113
|
+
"sampledata/payload-with-nulls.json",
|
114
|
+
"sampledata/payload.json"
|
115
|
+
],
|
116
|
+
"removed": [
|
117
|
+
"example-payload.json"
|
118
|
+
],
|
119
|
+
"modified": [
|
120
|
+
"payload.go",
|
121
|
+
"server.go"
|
122
|
+
]
|
123
|
+
},
|
124
|
+
"repository": {
|
125
|
+
"id": 10417548,
|
126
|
+
"name": "hookworm",
|
127
|
+
"url": "https://github.com/modcloth-labs/hookworm",
|
128
|
+
"description": "github hook receiving thingydoo",
|
129
|
+
"watchers": 0,
|
130
|
+
"stargazers": 0,
|
131
|
+
"forks": 0,
|
132
|
+
"fork": false,
|
133
|
+
"size": 208,
|
134
|
+
"owner": {
|
135
|
+
"name": "modcloth-labs",
|
136
|
+
"email": null
|
137
|
+
},
|
138
|
+
"private": false,
|
139
|
+
"open_issues": 0,
|
140
|
+
"has_issues": true,
|
141
|
+
"has_downloads": true,
|
142
|
+
"has_wiki": true,
|
143
|
+
"language": "Go",
|
144
|
+
"created_at": 1370060266,
|
145
|
+
"pushed_at": 1370191630,
|
146
|
+
"master_branch": "master",
|
147
|
+
"organization": "modcloth-labs"
|
148
|
+
},
|
149
|
+
"pusher": {
|
150
|
+
"name": "none"
|
151
|
+
},
|
152
|
+
"is_pr_merge": true
|
153
|
+
}
|