hookworm-handlers 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}
|