txgh-server 1.0.0.beta1
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 +7 -0
- data/lib/txgh-server/application.rb +141 -0
- data/lib/txgh-server/download_handler.rb +85 -0
- data/lib/txgh-server/github_request_auth.rb +28 -0
- data/lib/txgh-server/response.rb +15 -0
- data/lib/txgh-server/response_helpers.rb +26 -0
- data/lib/txgh-server/stream_response.rb +37 -0
- data/lib/txgh-server/tgz_stream_response.rb +39 -0
- data/lib/txgh-server/transifex_request_auth.rb +53 -0
- data/lib/txgh-server/triggers/handler.rb +50 -0
- data/lib/txgh-server/triggers/pull_handler.rb +18 -0
- data/lib/txgh-server/triggers/push_handler.rb +18 -0
- data/lib/txgh-server/triggers.rb +7 -0
- data/lib/txgh-server/version.rb +3 -0
- data/lib/txgh-server/webhooks/github/delete_handler.rb +37 -0
- data/lib/txgh-server/webhooks/github/handler.rb +20 -0
- data/lib/txgh-server/webhooks/github/ping_handler.rb +18 -0
- data/lib/txgh-server/webhooks/github/push_handler.rb +124 -0
- data/lib/txgh-server/webhooks/github/request_handler.rb +113 -0
- data/lib/txgh-server/webhooks/github.rb +11 -0
- data/lib/txgh-server/webhooks/transifex/hook_handler.rb +94 -0
- data/lib/txgh-server/webhooks/transifex/request_handler.rb +78 -0
- data/lib/txgh-server/webhooks/transifex.rb +8 -0
- data/lib/txgh-server/webhooks.rb +6 -0
- data/lib/txgh-server/zip_stream_response.rb +19 -0
- data/lib/txgh-server.rb +23 -0
- data/spec/application_spec.rb +347 -0
- data/spec/download_handler_spec.rb +91 -0
- data/spec/github_request_auth_spec.rb +39 -0
- data/spec/helpers/github_payload_builder.rb +141 -0
- data/spec/helpers/integration_setup.rb +47 -0
- data/spec/integration/cassettes/github_l10n_hook_endpoint.yml +536 -0
- data/spec/integration/cassettes/pull.yml +47 -0
- data/spec/integration/cassettes/push.yml +544 -0
- data/spec/integration/cassettes/transifex_hook_endpoint.yml +221 -0
- data/spec/integration/config/tx.config +10 -0
- data/spec/integration/hooks_spec.rb +159 -0
- data/spec/integration/payloads/github_postbody.json +161 -0
- data/spec/integration/payloads/github_postbody_l10n.json +136 -0
- data/spec/integration/payloads/github_postbody_release.json +136 -0
- data/spec/integration/triggers_spec.rb +45 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/tgz_stream_response_spec.rb +59 -0
- data/spec/transifex_request_auth_spec.rb +39 -0
- data/spec/webhooks/github/delete_handler_spec.rb +38 -0
- data/spec/webhooks/github/ping_handler_spec.rb +16 -0
- data/spec/webhooks/github/push_handler_spec.rb +106 -0
- data/spec/webhooks/transifex/hook_handler_spec.rb +136 -0
- data/spec/zip_stream_response_spec.rb +58 -0
- data/txgh-server.gemspec +24 -0
- metadata +170 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 2b139797c18ad7ef9fafb4b133c87955f4a43d51
|
|
4
|
+
data.tar.gz: c9adb77e0a0717ddd19c4dbad1c4d310a3d3638e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 0b66010e996e5b83b8b70fde64e11922df901979f0c796dbf953bc08b064e61cb54b25756f3491ab238dbaf7bda2476e6bf981109ab12d7babfa8397d7e889eb
|
|
7
|
+
data.tar.gz: c24933279950cbb05c47e20256895629cb92be9b7802f954b917d2f8e68f71bdf05c54e70880b93a0050c4b7fc81f709e93f92ad4a86a720f966303888bac432
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
require 'sinatra'
|
|
2
|
+
require 'sinatra/json'
|
|
3
|
+
require 'sinatra/reloader'
|
|
4
|
+
require 'sinatra/streaming'
|
|
5
|
+
|
|
6
|
+
module TxghServer
|
|
7
|
+
module RespondWith
|
|
8
|
+
def respond_with(resp)
|
|
9
|
+
env['txgh.response'] = resp
|
|
10
|
+
|
|
11
|
+
if resp.streaming?
|
|
12
|
+
response.headers.merge!(resp.headers)
|
|
13
|
+
|
|
14
|
+
stream do |out|
|
|
15
|
+
begin
|
|
16
|
+
resp.write_to(out)
|
|
17
|
+
rescue => e
|
|
18
|
+
Txgh.events.publish_error(e)
|
|
19
|
+
raise e
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
else
|
|
23
|
+
status resp.status
|
|
24
|
+
json resp.body
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class Application < Sinatra::Base
|
|
30
|
+
include TxghServer
|
|
31
|
+
|
|
32
|
+
helpers Sinatra::Streaming
|
|
33
|
+
helpers RespondWith
|
|
34
|
+
|
|
35
|
+
configure do
|
|
36
|
+
set :logging, nil
|
|
37
|
+
logger = Txgh::TxLogger.logger
|
|
38
|
+
set :logger, logger
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def initialize(app = nil)
|
|
42
|
+
super(app)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
get '/health_check' do
|
|
46
|
+
respond_with(
|
|
47
|
+
Response.new(200, {})
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
get '/config' do
|
|
52
|
+
config = Txgh::Config::KeyManager.config_from_project(params[:project_slug])
|
|
53
|
+
branch = Txgh::Utils.absolute_branch(params[:branch])
|
|
54
|
+
|
|
55
|
+
begin
|
|
56
|
+
tx_config = Txgh::Config::TxManager.tx_config(
|
|
57
|
+
config.transifex_project, config.github_repo, branch
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
data = tx_config.to_h
|
|
61
|
+
data.merge!(branch_slug: Txgh::Utils.slugify(branch)) if branch
|
|
62
|
+
|
|
63
|
+
status 200
|
|
64
|
+
json data: data
|
|
65
|
+
rescue Txgh::ConfigNotFoundError => e
|
|
66
|
+
status 404
|
|
67
|
+
json [{ error: e.message }]
|
|
68
|
+
rescue => e
|
|
69
|
+
status 500
|
|
70
|
+
json [{ error: e.message }]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
get '/download.:format' do
|
|
75
|
+
respond_with(
|
|
76
|
+
DownloadHandler.handle_request(request, settings.logger)
|
|
77
|
+
)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Hooks are protected endpoints used for data integration between Github and
|
|
82
|
+
# Transifex. They live under the /hooks namespace (see config.ru)
|
|
83
|
+
class WebhookEndpoints < Sinatra::Base
|
|
84
|
+
include TxghServer::Webhooks
|
|
85
|
+
helpers RespondWith
|
|
86
|
+
|
|
87
|
+
configure do
|
|
88
|
+
set :logging, nil
|
|
89
|
+
logger = Txgh::TxLogger.logger
|
|
90
|
+
set :logger, logger
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
configure :development do
|
|
94
|
+
register Sinatra::Reloader
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def initialize(app = nil)
|
|
98
|
+
super(app)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
post '/transifex' do
|
|
102
|
+
respond_with(
|
|
103
|
+
Transifex::RequestHandler.handle_request(request, settings.logger)
|
|
104
|
+
)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
post '/github' do
|
|
108
|
+
respond_with(
|
|
109
|
+
Github::RequestHandler.handle_request(request, settings.logger)
|
|
110
|
+
)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
class TriggerEndpoints < Sinatra::Base
|
|
115
|
+
include TxghServer::Triggers
|
|
116
|
+
|
|
117
|
+
helpers RespondWith
|
|
118
|
+
|
|
119
|
+
configure do
|
|
120
|
+
set :logging, nil
|
|
121
|
+
logger = Txgh::TxLogger.logger
|
|
122
|
+
set :logger, logger
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
configure :development do
|
|
126
|
+
register Sinatra::Reloader
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
patch '/push' do
|
|
130
|
+
respond_with(
|
|
131
|
+
PushHandler.handle_request(request, settings.logger)
|
|
132
|
+
)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
patch '/pull' do
|
|
136
|
+
respond_with(
|
|
137
|
+
PullHandler.handle_request(request, settings.logger)
|
|
138
|
+
)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
module TxghServer
|
|
2
|
+
class DownloadHandler
|
|
3
|
+
DEFAULT_FORMAT = '.zip'
|
|
4
|
+
|
|
5
|
+
# includes response helpers in both the class and the singleton class
|
|
6
|
+
include ResponseHelpers
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
def handle_request(request, logger = nil)
|
|
10
|
+
handle_safely do
|
|
11
|
+
config = config_from(request)
|
|
12
|
+
project, repo = [config.transifex_project, config.github_repo]
|
|
13
|
+
params = params_from(request)
|
|
14
|
+
handler = new(project, repo, params, logger)
|
|
15
|
+
handler.execute
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def config_from(request)
|
|
22
|
+
Txgh::Config::KeyManager.config_from_project(
|
|
23
|
+
request.params.fetch('project_slug')
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def params_from(request)
|
|
28
|
+
request.params.merge(
|
|
29
|
+
'format' => format_from(request)
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def format_from(request)
|
|
34
|
+
# sinatra is dumb and doesn't include any of the URL captures in the
|
|
35
|
+
# request params or env hash
|
|
36
|
+
File.extname(request.env['REQUEST_PATH'])
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def handle_safely
|
|
40
|
+
yield
|
|
41
|
+
rescue => e
|
|
42
|
+
respond_with_error(500, "Internal server error: #{e.message}", e)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
attr_reader :project, :repo, :params, :logger
|
|
47
|
+
|
|
48
|
+
def initialize(project, repo, params, logger)
|
|
49
|
+
@project = project
|
|
50
|
+
@repo = repo
|
|
51
|
+
@params = params
|
|
52
|
+
@logger = logger
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def execute
|
|
56
|
+
downloader = Txgh::ResourceDownloader.new(
|
|
57
|
+
project, repo, params['branch'], languages: project.languages
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
response_class.new(attachment, downloader.each)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def attachment
|
|
66
|
+
project.name
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def format
|
|
70
|
+
params.fetch('format', DEFAULT_FORMAT)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def response_class
|
|
74
|
+
case format
|
|
75
|
+
when '.zip'
|
|
76
|
+
ZipStreamResponse
|
|
77
|
+
when '.tgz'
|
|
78
|
+
TgzStreamResponse
|
|
79
|
+
else
|
|
80
|
+
raise TxghInternalError,
|
|
81
|
+
"'#{format}' is not a valid download format"
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'openssl'
|
|
2
|
+
|
|
3
|
+
module TxghServer
|
|
4
|
+
class GithubRequestAuth
|
|
5
|
+
HMAC_DIGEST = OpenSSL::Digest.new('sha1')
|
|
6
|
+
RACK_HEADER = 'HTTP_X_HUB_SIGNATURE'
|
|
7
|
+
GITHUB_HEADER = 'X-Hub-Signature'
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def authentic_request?(request, secret)
|
|
11
|
+
request.body.rewind
|
|
12
|
+
expected_signature = header_value(request.body.read, secret)
|
|
13
|
+
actual_signature = request.env[RACK_HEADER]
|
|
14
|
+
actual_signature == expected_signature
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def header_value(content, secret)
|
|
18
|
+
"sha1=#{digest(content, secret)}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def digest(content, secret)
|
|
24
|
+
OpenSSL::HMAC.hexdigest(HMAC_DIGEST, secret, content)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module TxghServer
|
|
2
|
+
module ResponseHelpers
|
|
3
|
+
private
|
|
4
|
+
|
|
5
|
+
def respond_with(status, body, e = nil)
|
|
6
|
+
TxghServer::Response.new(status, body, e)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def respond_with_error(status, message, e = nil)
|
|
10
|
+
respond_with(status, error(message), e)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def error(message)
|
|
14
|
+
[{ error: message }]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def data(body)
|
|
18
|
+
{ data: body }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# includes these methods in the singleton class as well
|
|
22
|
+
def self.included(base)
|
|
23
|
+
base.extend(self)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'mime/types'
|
|
2
|
+
|
|
3
|
+
module TxghServer
|
|
4
|
+
class StreamResponse
|
|
5
|
+
attr_reader :attachment, :enum
|
|
6
|
+
|
|
7
|
+
def initialize(attachment, enum)
|
|
8
|
+
@attachment = attachment
|
|
9
|
+
@enum = enum
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def write_to(stream)
|
|
13
|
+
raise NotImplementedError,
|
|
14
|
+
"please implement #{__method__} in derived classes"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def file_extension
|
|
18
|
+
raise NotImplementedError,
|
|
19
|
+
"please implement #{__method__} in derived classes"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def headers
|
|
23
|
+
@headers ||= {
|
|
24
|
+
'Content-Disposition' => "attachment; filename=\"#{attachment}#{file_extension}\"",
|
|
25
|
+
'Content-Type' => MIME::Types.type_for(file_extension).first.content_type
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def streaming?
|
|
30
|
+
true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def error
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'rubygems/package'
|
|
2
|
+
require 'stringio'
|
|
3
|
+
require 'zlib'
|
|
4
|
+
|
|
5
|
+
module TxghServer
|
|
6
|
+
class TgzStreamResponse < StreamResponse
|
|
7
|
+
PERMISSIONS = 0644
|
|
8
|
+
|
|
9
|
+
def write_to(stream)
|
|
10
|
+
Zlib::GzipWriter.wrap(stream) do |gz|
|
|
11
|
+
pipe = StringIO.new('', 'wb')
|
|
12
|
+
tar = Gem::Package::TarWriter.new(pipe)
|
|
13
|
+
|
|
14
|
+
enum.each do |file_name, contents|
|
|
15
|
+
tar.add_file(file_name, PERMISSIONS) do |f|
|
|
16
|
+
f.write(contents)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
flush(tar, pipe, gz)
|
|
20
|
+
stream.flush
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
flush(tar, pipe, gz)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def file_extension
|
|
28
|
+
'.tgz'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def flush(tar, pipe, gz)
|
|
34
|
+
tar.flush
|
|
35
|
+
gz.write(pipe.string)
|
|
36
|
+
pipe.reopen('')
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'openssl'
|
|
2
|
+
|
|
3
|
+
module TxghServer
|
|
4
|
+
class TransifexRequestAuth
|
|
5
|
+
HMAC_DIGEST = OpenSSL::Digest.new('sha1')
|
|
6
|
+
RACK_HEADER = 'HTTP_X_TX_SIGNATURE'
|
|
7
|
+
TRANSIFEX_HEADER = 'X-TX-Signature'
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def authentic_request?(request, secret)
|
|
11
|
+
request.body.rewind
|
|
12
|
+
expected_signature = header_value(request.body.read, secret)
|
|
13
|
+
actual_signature = request.env[RACK_HEADER]
|
|
14
|
+
actual_signature == expected_signature
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def header_value(content, secret)
|
|
18
|
+
digest(transform(content), secret)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
# In order to generate a correct HMAC hash, the request body must be
|
|
24
|
+
# parsed and made to look like a python map. If you're thinking that's
|
|
25
|
+
# weird, you're correct, but it's apparently expected behavior.
|
|
26
|
+
def transform(content)
|
|
27
|
+
params = URI.decode_www_form(content)
|
|
28
|
+
|
|
29
|
+
params = params.map do |key, val|
|
|
30
|
+
key = "'#{key}'"
|
|
31
|
+
val = interpret_val(val)
|
|
32
|
+
"#{key}: #{val}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
"{#{params.join(', ')}}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def interpret_val(val)
|
|
39
|
+
if val =~ /\A[\d]+\z/
|
|
40
|
+
val
|
|
41
|
+
else
|
|
42
|
+
"u'#{val}'"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def digest(content, secret)
|
|
47
|
+
Base64.encode64(
|
|
48
|
+
OpenSSL::HMAC.digest(HMAC_DIGEST, secret, content)
|
|
49
|
+
).strip
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module TxghServer
|
|
2
|
+
module Triggers
|
|
3
|
+
class Handler
|
|
4
|
+
|
|
5
|
+
# includes response helpers in both the class and the singleton class
|
|
6
|
+
include ResponseHelpers
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
def handle_request(request, logger)
|
|
10
|
+
handle_safely do
|
|
11
|
+
config = Txgh::Config::KeyManager.config_from_project(
|
|
12
|
+
request.params.fetch('project_slug')
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
handler_for(config, request, logger).execute
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def handle_safely
|
|
22
|
+
yield
|
|
23
|
+
rescue => e
|
|
24
|
+
respond_with_error(500, "Internal server error: #{e.message}", e)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def handler_for(config, request, logger)
|
|
28
|
+
new(
|
|
29
|
+
project: config.transifex_project,
|
|
30
|
+
repo: config.github_repo,
|
|
31
|
+
branch: request.params.fetch('branch'),
|
|
32
|
+
resource_slug: request.params.fetch('resource_slug'),
|
|
33
|
+
logger: logger
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
attr_reader :project, :repo, :branch, :resource_slug, :logger
|
|
39
|
+
|
|
40
|
+
def initialize(options = {})
|
|
41
|
+
@project = options[:project]
|
|
42
|
+
@repo = options[:repo]
|
|
43
|
+
@branch = Txgh::Utils.absolute_branch(options[:branch])
|
|
44
|
+
@resource_slug = options[:resource_slug]
|
|
45
|
+
@logger = options[:logger]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module TxghServer
|
|
2
|
+
module Triggers
|
|
3
|
+
class PullHandler < Handler
|
|
4
|
+
|
|
5
|
+
def execute
|
|
6
|
+
puller.pull_slug(resource_slug)
|
|
7
|
+
respond_with(200, true)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def puller
|
|
13
|
+
@puller ||= Txgh::Puller.new(project, repo, branch)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module TxghServer
|
|
2
|
+
module Triggers
|
|
3
|
+
class PushHandler < Handler
|
|
4
|
+
|
|
5
|
+
def execute
|
|
6
|
+
pusher.push_slug(resource_slug)
|
|
7
|
+
respond_with(200, true)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def pusher
|
|
13
|
+
@pusher ||= Txgh::Pusher.new(project, repo, branch)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module TxghServer
|
|
2
|
+
module Webhooks
|
|
3
|
+
module Github
|
|
4
|
+
class DeleteHandler < Handler
|
|
5
|
+
|
|
6
|
+
include Txgh::CategorySupport
|
|
7
|
+
|
|
8
|
+
def execute
|
|
9
|
+
perform_delete if should_handle_request?
|
|
10
|
+
respond_with(200, true)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def perform_delete
|
|
16
|
+
deleter.delete_resources
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def deleter
|
|
20
|
+
@deleter ||= Txgh::ResourceDeleter.new(project, repo, branch)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def should_handle_request?
|
|
24
|
+
# ref_type can be either 'branch' or 'tag' - we only care about branches
|
|
25
|
+
payload['ref_type'] == 'branch' &&
|
|
26
|
+
repo.should_process_ref?(branch) &&
|
|
27
|
+
project.auto_delete_resources?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def branch
|
|
31
|
+
Txgh::Utils.absolute_branch(payload['ref'].sub(/^refs\//, ''))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
|
|
3
|
+
module TxghServer
|
|
4
|
+
module Webhooks
|
|
5
|
+
module Github
|
|
6
|
+
class Handler
|
|
7
|
+
include ResponseHelpers
|
|
8
|
+
|
|
9
|
+
attr_reader :project, :repo, :payload, :logger
|
|
10
|
+
|
|
11
|
+
def initialize(options = {})
|
|
12
|
+
@project = options.fetch(:project)
|
|
13
|
+
@repo = options.fetch(:repo)
|
|
14
|
+
@payload = options.fetch(:payload)
|
|
15
|
+
@logger = options.fetch(:logger) { Logger.new(STDOUT) }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module TxghServer
|
|
2
|
+
module Webhooks
|
|
3
|
+
module Github
|
|
4
|
+
# Handles github's ping event, which is a test event fired whenever a new
|
|
5
|
+
# webhook is set up.
|
|
6
|
+
class PingHandler
|
|
7
|
+
include ResponseHelpers
|
|
8
|
+
|
|
9
|
+
def initialize(options = {})
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def execute
|
|
13
|
+
respond_with(200, {})
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|