github-event-watcher 1.0.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 +7 -0
- data/.gitignore +2 -0
- data/.travis.yml +8 -0
- data/Gemfile +3 -0
- data/README.md +48 -0
- data/Rakefile +23 -0
- data/bin/github-pull-push-events +21 -0
- data/config.yaml.example +4 -0
- data/github-event-watcher.gemspec +25 -0
- data/lib/github-event-watcher.rb +22 -0
- data/lib/github-event-watcher/command/github-pull-push-events.rb +179 -0
- data/lib/github-event-watcher/event.rb +55 -0
- data/lib/github-event-watcher/persistent-state.rb +53 -0
- data/lib/github-event-watcher/version.rb +18 -0
- data/lib/github-event-watcher/watcher.rb +88 -0
- data/lib/github-event-watcher/webhook-sender.rb +74 -0
- metadata +130 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fbbc0e39a43cb1d647f242f828e71aa38577e32e
|
4
|
+
data.tar.gz: 1c1d8274a79420feb01506eca2f121adad53e737
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d49f46fc9782cc848954fb4bdc80a6aa1eca0f3a82cfbfc6f9e893eef3ff019c13acb7b4e9e3d079b069105de807a32e7bd4388a5d0fba94281d49d8d25f930d
|
7
|
+
data.tar.gz: 2418a9cac647a5d83945d61298515e8447d879d39861689c1d0b40102c5bbf702a49d88904bbc2f1982711488e2cb195e1018eab633bf3d52114583750dbef9d
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
[](https://travis-ci.org/clear-code/github-event-watcher)
|
2
|
+
|
3
|
+
# README
|
4
|
+
|
5
|
+
## Name
|
6
|
+
|
7
|
+
github-event-watcher
|
8
|
+
|
9
|
+
## Description
|
10
|
+
|
11
|
+
This package is for developers who want to watch GitHub repositories
|
12
|
+
of other people. You can't set
|
13
|
+
[GitHub Webhooks](https://developer.github.com/webhooks/) for GitHub
|
14
|
+
repositories of other people.
|
15
|
+
|
16
|
+
This package pulls events from GitHub and sends GitHub compatible
|
17
|
+
(subset) POST request to your Webhooks.
|
18
|
+
|
19
|
+
You can implement commit mail by using with
|
20
|
+
[GitHub POST receiver at clear-code/git-utils](https://github.com/clear-code/git-utils/tree/master/github-post-receiver).
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
% git clone https://github.com/clear-code/git-utils.git
|
25
|
+
% cd github-event-watcher
|
26
|
+
% cp config.yaml{.example,}
|
27
|
+
% editor config.yaml
|
28
|
+
% ruby -I lib bin/github-pull-push-events --daemon
|
29
|
+
|
30
|
+
`config.yaml` uses the following format:
|
31
|
+
|
32
|
+
repositories:
|
33
|
+
- clear-code/git-utils
|
34
|
+
- ruby/ruby
|
35
|
+
- rails/rails
|
36
|
+
webhook-end-point: http://git-utils.example.com/post-receiver/
|
37
|
+
|
38
|
+
List repositories by `${owner}/${name}` format into `repositories`.
|
39
|
+
|
40
|
+
Specify your GitHub Webhook receiver URL to `webhook-end-point`.
|
41
|
+
|
42
|
+
## Authors
|
43
|
+
|
44
|
+
* Kouhei Sutou `<kou@clear-code.com>`
|
45
|
+
|
46
|
+
## License
|
47
|
+
|
48
|
+
GPLv3 or later.
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Copyright (C) 2012-2013 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require "bundler/gem_tasks"
|
17
|
+
|
18
|
+
task :default => :test
|
19
|
+
|
20
|
+
desc "Run test"
|
21
|
+
task :test do
|
22
|
+
ruby("test/run-test.rb")
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (C) 2014 Kouhei Sutou <kou@clear-code.com>
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
require "github-event-watcher"
|
19
|
+
|
20
|
+
command = GitHubEventWatcher::Command::GitHubPullPushEvents.new
|
21
|
+
exit(command.run)
|
data/config.yaml.example
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'github-event-watcher/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "github-event-watcher"
|
7
|
+
spec.version = GitHubEventWatcher::VERSION
|
8
|
+
spec.authors = ["Kouhei Sutou"]
|
9
|
+
spec.email = ["kou@clear-code.com"]
|
10
|
+
spec.summary = %q{GitHub event watcher}
|
11
|
+
spec.description = %q{GitHub event watcher}
|
12
|
+
spec.homepage = ""
|
13
|
+
spec.license = "GPL-3.0+"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler"
|
21
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
+
spec.add_development_dependency "test-unit"
|
23
|
+
spec.add_development_dependency "test-unit-rr"
|
24
|
+
spec.add_development_dependency "test-unit-capybara"
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Copyright (C) 2014 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require "github-event-watcher/event"
|
17
|
+
require "github-event-watcher/persistent-state"
|
18
|
+
require "github-event-watcher/version"
|
19
|
+
require "github-event-watcher/watcher"
|
20
|
+
require "github-event-watcher/webhook-sender"
|
21
|
+
|
22
|
+
require "github-event-watcher/command/github-pull-push-events"
|
@@ -0,0 +1,179 @@
|
|
1
|
+
# Copyright (C) 2014 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require "optparse"
|
17
|
+
require "fileutils"
|
18
|
+
require "pathname"
|
19
|
+
require "time"
|
20
|
+
require "logger"
|
21
|
+
require "yaml"
|
22
|
+
|
23
|
+
require "github-event-watcher"
|
24
|
+
|
25
|
+
module GitHubEventWatcher
|
26
|
+
module Command
|
27
|
+
class GitHubPullPushEvents
|
28
|
+
def initialize
|
29
|
+
@state_dir = Pathname.new("var/lib")
|
30
|
+
@log_dir = Pathname.new("var/log")
|
31
|
+
@config_file = Pathname.new("config.yaml")
|
32
|
+
@pid_file = Pathname.new("var/run/github-pull-push-events.pid")
|
33
|
+
@daemonize = false
|
34
|
+
end
|
35
|
+
|
36
|
+
def run(argv=ARGV)
|
37
|
+
parse_command_line!(argv)
|
38
|
+
expand_paths
|
39
|
+
start_watcher
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def parse_command_line!(argv)
|
45
|
+
parser = OptionParser.new
|
46
|
+
parser.version = VERSION
|
47
|
+
parser.on("--state-dir=DIR",
|
48
|
+
"The directory to store state file",
|
49
|
+
"(#{@state_dir})") do |dir|
|
50
|
+
@state_dir = Pathname.new(dir)
|
51
|
+
end
|
52
|
+
parser.on("--log-dir=DIR",
|
53
|
+
"The directory to store logs",
|
54
|
+
"(#{@log_dir})") do |dir|
|
55
|
+
@log_dir = Pathname.new(dir)
|
56
|
+
end
|
57
|
+
parser.on("--config-file=FILE",
|
58
|
+
"The config file in YAML",
|
59
|
+
"(#{@config_file})") do |file|
|
60
|
+
@config_file = Pathname.new(file)
|
61
|
+
end
|
62
|
+
parser.on("--pid-file=FILE",
|
63
|
+
"The PID file",
|
64
|
+
"(#{@pid_file})") do |file|
|
65
|
+
@pid_file = Pathname.new(file)
|
66
|
+
end
|
67
|
+
parser.on("--[no-]daemonize",
|
68
|
+
"Run as a daemon",
|
69
|
+
"(#{@daemonize})") do |boolean|
|
70
|
+
@daemonize = boolean
|
71
|
+
end
|
72
|
+
parser.parse!(argv)
|
73
|
+
end
|
74
|
+
|
75
|
+
def expand_paths
|
76
|
+
@state_dir = @state_dir.expand_path
|
77
|
+
@log_dir = @log_dir.expand_path
|
78
|
+
@config_file = @config_file.expand_path
|
79
|
+
@pid_file = @pid_file.expand_path
|
80
|
+
end
|
81
|
+
|
82
|
+
def start_watcher
|
83
|
+
state = create_state
|
84
|
+
logger = create_logger
|
85
|
+
watcher = Watcher.new(state, logger)
|
86
|
+
config = load_config
|
87
|
+
config["repositories"].each do |repository|
|
88
|
+
watcher.add_repository(repository)
|
89
|
+
end
|
90
|
+
webhook_end_point = URI.parse(config["webhook-end-point"])
|
91
|
+
webhook_sender = WebhookSender.new(webhook_end_point, logger)
|
92
|
+
|
93
|
+
setup_signals(watcher)
|
94
|
+
|
95
|
+
if @daemonize
|
96
|
+
Process.daemon
|
97
|
+
$stdout = create_io_logger("stdout")
|
98
|
+
$stderr = create_io_logger("stderr")
|
99
|
+
at_exit do
|
100
|
+
$stdout.flush
|
101
|
+
$stderr.flush
|
102
|
+
end
|
103
|
+
end
|
104
|
+
create_pid_file
|
105
|
+
|
106
|
+
begin
|
107
|
+
watcher.watch do |event|
|
108
|
+
next if event.type != "PushEvent"
|
109
|
+
webhook_sender.send_push_event(event)
|
110
|
+
end
|
111
|
+
ensure
|
112
|
+
remove_pid_file
|
113
|
+
end
|
114
|
+
|
115
|
+
logger.close
|
116
|
+
end
|
117
|
+
|
118
|
+
def create_state
|
119
|
+
FileUtils.mkdir_p(@state_dir.to_s)
|
120
|
+
PersistentState.new(@state_dir + "state.yaml")
|
121
|
+
end
|
122
|
+
|
123
|
+
def create_logger(type=nil)
|
124
|
+
FileUtils.mkdir_p(@log_dir.to_s)
|
125
|
+
components = ["github-pull-push-events", type, "log"].compact
|
126
|
+
log_file = @log_dir + components.join(".")
|
127
|
+
logger = Logger.new(log_file.to_s, 10, 1024 ** 2)
|
128
|
+
logger.level = Logger::INFO
|
129
|
+
logger.formatter = lambda do |severity, timestamp, program_name, message|
|
130
|
+
"#{timestamp.iso8601}[#{severity.downcase}] #{message}\n"
|
131
|
+
end
|
132
|
+
logger
|
133
|
+
end
|
134
|
+
|
135
|
+
def create_io_logger(type)
|
136
|
+
logger = create_logger(type)
|
137
|
+
logger.level = Logger::DEBUG
|
138
|
+
class << logger
|
139
|
+
def write(message)
|
140
|
+
message = message.strip
|
141
|
+
return if message.empty?
|
142
|
+
debug(message)
|
143
|
+
end
|
144
|
+
|
145
|
+
def flush
|
146
|
+
return if @logdev.nil?
|
147
|
+
@logdev.dev.flush
|
148
|
+
end
|
149
|
+
end
|
150
|
+
logger
|
151
|
+
end
|
152
|
+
|
153
|
+
def load_config
|
154
|
+
YAML.load(@config_file.read)
|
155
|
+
end
|
156
|
+
|
157
|
+
def setup_signals(watcher)
|
158
|
+
trap(:INT) do
|
159
|
+
watcher.stop
|
160
|
+
end
|
161
|
+
trap(:TERM) do
|
162
|
+
watcher.stop
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def create_pid_file
|
167
|
+
FileUtils.mkdir_p(@pid_file.dirname.to_s)
|
168
|
+
@pid_file.open("w") do |pid_file|
|
169
|
+
pid_file.print(Process.pid)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def remove_pid_file
|
174
|
+
return unless @pid_file.exist?
|
175
|
+
FileUtils.rm_f(@pid_file.to_s)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# Copyright (C) 2014 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
module GitHubEventWatcher
|
17
|
+
class Event
|
18
|
+
def initialize(data)
|
19
|
+
@data = data
|
20
|
+
@repository = @data["repo"]
|
21
|
+
end
|
22
|
+
|
23
|
+
def id
|
24
|
+
Integer(@data["id"])
|
25
|
+
end
|
26
|
+
|
27
|
+
def type
|
28
|
+
@data["type"]
|
29
|
+
end
|
30
|
+
|
31
|
+
def payload
|
32
|
+
@data["payload"]
|
33
|
+
end
|
34
|
+
|
35
|
+
def repository_url
|
36
|
+
"https://github.com/#{repository_full_name}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def repository_owner
|
40
|
+
owner, name = repository_full_name.split("/", 2)
|
41
|
+
_ = name # For suppressing a warning
|
42
|
+
owner
|
43
|
+
end
|
44
|
+
|
45
|
+
def repository_name
|
46
|
+
owner, name = repository_full_name.split("/", 2)
|
47
|
+
_ = owner # For suppressing a warning
|
48
|
+
name
|
49
|
+
end
|
50
|
+
|
51
|
+
def repository_full_name
|
52
|
+
@repository["name"]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Copyright (C) 2014 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require "yaml"
|
17
|
+
|
18
|
+
module GitHubEventWatcher
|
19
|
+
class PersistentState
|
20
|
+
def initialize(path)
|
21
|
+
@path = path
|
22
|
+
load
|
23
|
+
end
|
24
|
+
|
25
|
+
def processed_event_id(repository_name)
|
26
|
+
repository(repository_name)["processed-event-id"] || 0
|
27
|
+
end
|
28
|
+
|
29
|
+
def update_processed_event_id(repository_name, id)
|
30
|
+
repository(repository_name)["processed-event-id"] = id
|
31
|
+
save
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def repository(name)
|
36
|
+
@repositories[name] ||= {}
|
37
|
+
end
|
38
|
+
|
39
|
+
def load
|
40
|
+
if @path.exist?
|
41
|
+
@repositories = YAML.load(@path.read)
|
42
|
+
else
|
43
|
+
@repositories = {}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def save
|
48
|
+
@path.open("w") do |file|
|
49
|
+
file.print(@repositories.to_yaml)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Copyright (C) 2014 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
module GitHubEventWatcher
|
17
|
+
VERSION = "1.0.0"
|
18
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# Copyright (C) 2014-2015 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require "open-uri"
|
17
|
+
require "json"
|
18
|
+
|
19
|
+
require "github-event-watcher/event"
|
20
|
+
|
21
|
+
module GitHubEventWatcher
|
22
|
+
class Watcher
|
23
|
+
NOTIFY_MESSAGE = "X"
|
24
|
+
|
25
|
+
def initialize(state, logger)
|
26
|
+
@repositories = []
|
27
|
+
@state = state
|
28
|
+
@logger = logger
|
29
|
+
@running = true
|
30
|
+
@notify_pipe = IO.pipe
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_repository(name)
|
34
|
+
@logger.info("[watcher][repository] add: <#{name}>")
|
35
|
+
@repositories << name
|
36
|
+
end
|
37
|
+
|
38
|
+
def watch
|
39
|
+
i = 0
|
40
|
+
while @running
|
41
|
+
name = @repositories[i]
|
42
|
+
events = fetch_events(name)
|
43
|
+
processed_event_id = @state.processed_event_id(name)
|
44
|
+
events = remove_processed_events(events, processed_event_id)
|
45
|
+
@logger.info("[watcher][watch][#{name}] target events: <#{events.size}>")
|
46
|
+
sorted_events = events.sort_by do |event|
|
47
|
+
event.id
|
48
|
+
end
|
49
|
+
sorted_events.each do |event|
|
50
|
+
yield(event)
|
51
|
+
end
|
52
|
+
latest_event = sorted_events.last
|
53
|
+
if latest_event
|
54
|
+
@logger.info("[watcher][watch][#{name}] last processed event ID: " +
|
55
|
+
"<#{latest_event.id}>")
|
56
|
+
@state.update_processed_event_id(name, latest_event.id)
|
57
|
+
end
|
58
|
+
readables, = IO.select([@notify_pipe[0]], nil, nil, 60)
|
59
|
+
readables[0].read(NOTIFY_MESSAGE.size) if readables
|
60
|
+
i = (i + 1) % @repositories.size
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def stop
|
65
|
+
@running = false
|
66
|
+
@notify_pipe[1].write(NOTIFY_MESSAGE)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
def fetch_events(name)
|
71
|
+
open("https://api.github.com/repos/#{name}/events") do |body|
|
72
|
+
JSON.parse(body.read).collect do |event|
|
73
|
+
Event.new(event)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
rescue OpenURI::HTTPError, SystemCallError, Timeout::Error
|
77
|
+
tag = "[watcher][watch][#{name}][fetch]"
|
78
|
+
@logger.error("#{tag} Failed to fetch: #{$!.class}: #{$!.message}")
|
79
|
+
[]
|
80
|
+
end
|
81
|
+
|
82
|
+
def remove_processed_events(events, processed_event_id)
|
83
|
+
events.reject do |event|
|
84
|
+
event.id <= processed_event_id
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Copyright (C) 2014 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require "net/http"
|
17
|
+
require "json"
|
18
|
+
|
19
|
+
module GitHubEventWatcher
|
20
|
+
class WebhookSender
|
21
|
+
def initialize(end_point, logger)
|
22
|
+
@end_point = end_point
|
23
|
+
@logger = logger
|
24
|
+
@logger.info("[webhook-sender][end-point] <#{@end_point}>")
|
25
|
+
end
|
26
|
+
|
27
|
+
def send_push_event(event)
|
28
|
+
@logger.info("[webhook-sender][send][push] " +
|
29
|
+
"<#{event.id}>:<#{event.repository_full_name}>")
|
30
|
+
options = {
|
31
|
+
:use_ssl => (@end_point.scheme == "https"),
|
32
|
+
}
|
33
|
+
begin
|
34
|
+
Net::HTTP.start(@end_point.host, @end_point.port, options) do |http|
|
35
|
+
request = Net::HTTP::Post.new(@end_point.request_uri)
|
36
|
+
request["Host"] = @end_point.hostname
|
37
|
+
request["X-GitHub-Event"] = "push"
|
38
|
+
request["Content-Type"] = "application/json"
|
39
|
+
request["User-Agent"] = "GitHub Event Watcher/1.0"
|
40
|
+
request.body = JSON.generate(convert_to_push_event_payload(event))
|
41
|
+
response = http.request(request)
|
42
|
+
log_tag = "[webhook-sender][sent][push]"
|
43
|
+
case response
|
44
|
+
when Net::HTTPSuccess
|
45
|
+
@logger.info("#{log_tag}[success]")
|
46
|
+
else
|
47
|
+
@logger.error("#{log_tag}[error] <#{response.code}>")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
rescue SystemCallError, Timeout::Error
|
51
|
+
tag = "[webhook-sender][send][push][error]"
|
52
|
+
message = "#{tag} Failed to send push event: #{$!.class}: #{$!.message}"
|
53
|
+
@logger.error(message)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def convert_to_push_event_payload(event)
|
59
|
+
{
|
60
|
+
"ref" => event.payload["ref"],
|
61
|
+
"before" => event.payload["before"],
|
62
|
+
"after" => event.payload["head"],
|
63
|
+
"repository" => {
|
64
|
+
"url" => event.repository_url,
|
65
|
+
"name" => event.repository_name,
|
66
|
+
"full_name" => event.repository_full_name,
|
67
|
+
"owner" => {
|
68
|
+
"name" => event.repository_owner,
|
69
|
+
},
|
70
|
+
},
|
71
|
+
}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: github-event-watcher
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kouhei Sutou
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: test-unit
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: test-unit-rr
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: test-unit-capybara
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: GitHub event watcher
|
84
|
+
email:
|
85
|
+
- kou@clear-code.com
|
86
|
+
executables:
|
87
|
+
- github-pull-push-events
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- ".gitignore"
|
92
|
+
- ".travis.yml"
|
93
|
+
- Gemfile
|
94
|
+
- README.md
|
95
|
+
- Rakefile
|
96
|
+
- bin/github-pull-push-events
|
97
|
+
- config.yaml.example
|
98
|
+
- github-event-watcher.gemspec
|
99
|
+
- lib/github-event-watcher.rb
|
100
|
+
- lib/github-event-watcher/command/github-pull-push-events.rb
|
101
|
+
- lib/github-event-watcher/event.rb
|
102
|
+
- lib/github-event-watcher/persistent-state.rb
|
103
|
+
- lib/github-event-watcher/version.rb
|
104
|
+
- lib/github-event-watcher/watcher.rb
|
105
|
+
- lib/github-event-watcher/webhook-sender.rb
|
106
|
+
homepage: ''
|
107
|
+
licenses:
|
108
|
+
- GPL-3.0+
|
109
|
+
metadata: {}
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options: []
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 2.4.5
|
127
|
+
signing_key:
|
128
|
+
specification_version: 4
|
129
|
+
summary: GitHub event watcher
|
130
|
+
test_files: []
|