octospy 0.0.1
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 +19 -0
- data/.rspec +1 -0
- data/.travis.yml +23 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +58 -0
- data/Rakefile +4 -0
- data/bin/octospy +6 -0
- data/lib/cinch/plugins/management.rb +91 -0
- data/lib/cinch/plugins/octospy/job.rb +97 -0
- data/lib/cinch/plugins/octospy/recording.rb +101 -0
- data/lib/cinch/plugins/octospy.rb +68 -0
- data/lib/octospy/configurable.rb +49 -0
- data/lib/octospy/extensions/string.rb +39 -0
- data/lib/octospy/octokit/client.rb +9 -0
- data/lib/octospy/parser/download.rb +13 -0
- data/lib/octospy/parser/gist.rb +20 -0
- data/lib/octospy/parser/issue.rb +43 -0
- data/lib/octospy/parser/organization.rb +22 -0
- data/lib/octospy/parser/pull_request.rb +32 -0
- data/lib/octospy/parser/repository.rb +80 -0
- data/lib/octospy/parser/user.rb +37 -0
- data/lib/octospy/parser/wiki.rb +19 -0
- data/lib/octospy/parser.rb +117 -0
- data/lib/octospy/recordable/channel.rb +23 -0
- data/lib/octospy/recordable/repo.rb +16 -0
- data/lib/octospy/recordable.rb +26 -0
- data/lib/octospy/shortener.rb +48 -0
- data/lib/octospy/version.rb +3 -0
- data/lib/octospy/worker.rb +48 -0
- data/lib/octospy.rb +55 -0
- data/octospy.gemspec +37 -0
- data/spec/fixtures/commit_comment_event.json +59 -0
- data/spec/fixtures/create_event.json +21 -0
- data/spec/fixtures/delete_event.json +23 -0
- data/spec/fixtures/follow_event.json +48 -0
- data/spec/fixtures/fork_event.json +139 -0
- data/spec/fixtures/gist_event.json +27 -0
- data/spec/fixtures/gollum_event.json +30 -0
- data/spec/fixtures/issue_comment_event.json +97 -0
- data/spec/fixtures/issues_event.json +70 -0
- data/spec/fixtures/member_event.json +39 -0
- data/spec/fixtures/public_event.json +16 -0
- data/spec/fixtures/pull_request_event.json +400 -0
- data/spec/fixtures/pull_request_review_comment_event.json +73 -0
- data/spec/fixtures/push_event.json +35 -0
- data/spec/fixtures/team_add_event.json +51 -0
- data/spec/fixtures/watch_event.json +23 -0
- data/spec/helper.rb +79 -0
- data/spec/octospy/extensions/string_spec.rb +84 -0
- data/spec/octospy/parser/download_spec.rb +9 -0
- data/spec/octospy/parser/gist_spec.rb +17 -0
- data/spec/octospy/parser/issue_spec.rb +33 -0
- data/spec/octospy/parser/organization_spec.rb +33 -0
- data/spec/octospy/parser/pull_request_spec.rb +33 -0
- data/spec/octospy/parser/repository_spec.rb +101 -0
- data/spec/octospy/parser/user_spec.rb +44 -0
- data/spec/octospy/parser/wiki_spec.rb +17 -0
- data/spec/octospy/parser_spec.rb +63 -0
- data/spec/octospy/shortener_spec.rb +46 -0
- data/spec/support/shared_context.rb +60 -0
- metadata +345 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 47c3a44346c54c0c69fb51561b692fb4f9216304
|
4
|
+
data.tar.gz: 80c043163646771135069da36e087dc01cab75c7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d19a444802e932594a9513605314cd665bc85274f12d9a22a5892d9902cb327ee8279979e28f0ef79f3bd468b3b7818069438bea923c20bac07533da16a6ef0d
|
7
|
+
data.tar.gz: 25694444c3dd360c39f1fa2549ca27795da1aaff97704b556502b04c2c4784f4bcf3fe4820cd962441a1f01dc150628086fde0f7996b8986bcb1d19d5d7b9ff5
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
language: ruby
|
2
|
+
|
3
|
+
rvm:
|
4
|
+
- 1.9.3
|
5
|
+
- 2.0.0
|
6
|
+
|
7
|
+
before_install:
|
8
|
+
- gem update bundler
|
9
|
+
|
10
|
+
script:
|
11
|
+
- bundle exec rake spec
|
12
|
+
|
13
|
+
notifications:
|
14
|
+
email:
|
15
|
+
recipients:
|
16
|
+
- linyows@gmail.com
|
17
|
+
on_success: change
|
18
|
+
on_failure: always
|
19
|
+
irc:
|
20
|
+
on_success: change
|
21
|
+
on_failure: always
|
22
|
+
channels:
|
23
|
+
- "irc.freenode.org#linyows"
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 linyows
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
Octospy
|
2
|
+
=======
|
3
|
+
|
4
|
+
[][gem]
|
5
|
+
[][travis]
|
6
|
+
[][gemnasium]
|
7
|
+
[][codeclimate]
|
8
|
+
[][coveralls]
|
9
|
+
|
10
|
+
[gem]: https://rubygems.org/gems/octospy
|
11
|
+
[travis]: http://travis-ci.org/linyows/octospy
|
12
|
+
[gemnasium]: https://gemnasium.com/linyows/octospy
|
13
|
+
[codeclimate]: https://codeclimate.com/github/linyows/octospy
|
14
|
+
[coveralls]: https://coveralls.io/r/linyows/octospy
|
15
|
+
|
16
|
+
Octospy notifies the repository activity to an IRC channel.
|
17
|
+
|
18
|
+
<img src="http://octodex.github.com/images/daftpunktocat-thomas.gif" width="300">
|
19
|
+
<img src="http://octodex.github.com/images/daftpunktocat-guy.gif" width="300">
|
20
|
+
|
21
|
+
Installation
|
22
|
+
------------
|
23
|
+
|
24
|
+
Add this line to your application's Gemfile:
|
25
|
+
|
26
|
+
gem 'octospy'
|
27
|
+
|
28
|
+
And then execute:
|
29
|
+
|
30
|
+
$ bundle
|
31
|
+
|
32
|
+
Or install it yourself as:
|
33
|
+
|
34
|
+
$ gem install octospy
|
35
|
+
|
36
|
+
Usage
|
37
|
+
-----
|
38
|
+
|
39
|
+
TODO: Write usage instructions here
|
40
|
+
|
41
|
+
Contributing
|
42
|
+
------------
|
43
|
+
|
44
|
+
1. Fork it
|
45
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
46
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
47
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
48
|
+
5. Create new Pull Request
|
49
|
+
|
50
|
+
Author
|
51
|
+
------
|
52
|
+
|
53
|
+
- [linyows](https://github.com/linyows)
|
54
|
+
|
55
|
+
License
|
56
|
+
-------
|
57
|
+
|
58
|
+
MIT
|
data/Rakefile
ADDED
data/bin/octospy
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
module Cinch
|
2
|
+
module Plugins
|
3
|
+
class Management
|
4
|
+
include Cinch::Plugin
|
5
|
+
|
6
|
+
match(/plugin load (\S+)(?: (\S+))?/, method: :load_plugin)
|
7
|
+
match(/plugin unload (\S+)/, method: :unload_plugin)
|
8
|
+
match(/plugin reload (\S+)(?: (\S+))?/, method: :reload_plugin)
|
9
|
+
match(/plugin set (\S+) (\S+) (.+)$/, method: :set_option)
|
10
|
+
def load_plugin(m, plugin, mapping)
|
11
|
+
mapping ||= plugin.gsub(/(.)([A-Z])/) { |_|
|
12
|
+
$1 + "_" + $2
|
13
|
+
}.downcase # we downcase here to also catch the first letter
|
14
|
+
|
15
|
+
file_name = "lib/cinch/plugins/#{mapping}.rb"
|
16
|
+
unless File.exist?(file_name)
|
17
|
+
m.reply "Could not load #{plugin} because #{file_name} does not exist."
|
18
|
+
return
|
19
|
+
end
|
20
|
+
|
21
|
+
begin
|
22
|
+
load(file_name)
|
23
|
+
rescue
|
24
|
+
m.reply "Could not load #{plugin}."
|
25
|
+
raise
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
const = Cinch::Plugins.const_get(plugin)
|
30
|
+
rescue NameError
|
31
|
+
m.reply "Could not load #{plugin} because no matching class was found."
|
32
|
+
return
|
33
|
+
end
|
34
|
+
|
35
|
+
@bot.plugins.register_plugin(const)
|
36
|
+
m.reply "Successfully loaded #{plugin}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def unload_plugin(m, plugin)
|
40
|
+
begin
|
41
|
+
plugin_class = Cinch::Plugins.const_get(plugin)
|
42
|
+
rescue NameError
|
43
|
+
m.reply "Could not unload #{plugin} because no matching class was found."
|
44
|
+
return
|
45
|
+
end
|
46
|
+
|
47
|
+
@bot.plugins.select {|p| p.class == plugin_class}.each do |p|
|
48
|
+
@bot.plugins.unregister_plugin(p)
|
49
|
+
end
|
50
|
+
|
51
|
+
## FIXME not doing this at the moment because it'll break
|
52
|
+
## plugin options. This means, however, that reloading a
|
53
|
+
## plugin is relatively dirty: old methods will not be removed
|
54
|
+
## but only overwritten by new ones. You will also not be able
|
55
|
+
## to change a classes superclass this way.
|
56
|
+
# Cinch::Plugins.__send__(:remove_const, plugin)
|
57
|
+
|
58
|
+
# Because we're not completely removing the plugin class,
|
59
|
+
# reset everything to the starting values.
|
60
|
+
plugin_class.hooks.clear
|
61
|
+
plugin_class.matchers.clear
|
62
|
+
plugin_class.listeners.clear
|
63
|
+
plugin_class.timers.clear
|
64
|
+
plugin_class.ctcps.clear
|
65
|
+
plugin_class.react_on = :message
|
66
|
+
plugin_class.plugin_name = nil
|
67
|
+
plugin_class.help = nil
|
68
|
+
plugin_class.prefix = nil
|
69
|
+
plugin_class.suffix = nil
|
70
|
+
plugin_class.required_options.clear
|
71
|
+
|
72
|
+
m.reply "Successfully unloaded #{plugin}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def reload_plugin(m, plugin, mapping)
|
76
|
+
unload_plugin(m, plugin)
|
77
|
+
load_plugin(m, plugin, mapping)
|
78
|
+
end
|
79
|
+
|
80
|
+
def set_option(m, plugin, option, value)
|
81
|
+
begin
|
82
|
+
const = Cinch::Plugins.const_get(plugin)
|
83
|
+
rescue NameError
|
84
|
+
m.reply "Could not set plugin option for #{plugin} because no matching class was found."
|
85
|
+
return
|
86
|
+
end
|
87
|
+
@bot.config.plugins.options[const][option.to_sym] = eval(value)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'octospy'
|
2
|
+
|
3
|
+
module Cinch
|
4
|
+
module Plugins
|
5
|
+
class Octospy
|
6
|
+
module Job
|
7
|
+
def self.included(base)
|
8
|
+
base.class_eval do
|
9
|
+
match('job start', method: :start_with_message)
|
10
|
+
match('job stop', method: :stop_with_message)
|
11
|
+
match('job restart', method: :restart_with_message)
|
12
|
+
end
|
13
|
+
|
14
|
+
Channel.class_eval do
|
15
|
+
attr_accessor :job_thread, :last_github_event_id
|
16
|
+
|
17
|
+
define_method(:job_thread_alive?) do
|
18
|
+
@job_thread && @job_thread.alive?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def start_with_message(m)
|
24
|
+
if m.channel.job_thread_alive?
|
25
|
+
m.reply 'I have already started'
|
26
|
+
return
|
27
|
+
end
|
28
|
+
|
29
|
+
start(m)
|
30
|
+
m.reply 'I started'
|
31
|
+
end
|
32
|
+
|
33
|
+
def stop_with_message(m)
|
34
|
+
unless m.channel.job_thread_alive?
|
35
|
+
m.reply 'I have not started'
|
36
|
+
return
|
37
|
+
end
|
38
|
+
|
39
|
+
stop(m)
|
40
|
+
m.reply 'I stopped'
|
41
|
+
end
|
42
|
+
|
43
|
+
def restart_with_message(m)
|
44
|
+
if restart(m)
|
45
|
+
m.reply 'I restarted'
|
46
|
+
else
|
47
|
+
m.reply 'I have not started'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def start(m)
|
52
|
+
repos = ::Octospy.channel(m.channel.name).repos
|
53
|
+
channel = m.channel
|
54
|
+
|
55
|
+
worker = ::Octospy.worker(repos) do |message|
|
56
|
+
case message.class.name
|
57
|
+
when 'String'
|
58
|
+
message.each_char.each_slice(512) do |string|
|
59
|
+
channel.notice string.join
|
60
|
+
sleep 1
|
61
|
+
end
|
62
|
+
when 'Array'
|
63
|
+
message.each do |line|
|
64
|
+
# maximum line length 512
|
65
|
+
# http://www.mirc.com/rfc2812.html
|
66
|
+
line.each_char.each_slice(512) do |string|
|
67
|
+
channel.notice string.join
|
68
|
+
sleep 1
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
m.channel.job_thread = worker.thread
|
75
|
+
end
|
76
|
+
|
77
|
+
def stop(m)
|
78
|
+
m.channel.job_thread.kill
|
79
|
+
end
|
80
|
+
|
81
|
+
def restart(m)
|
82
|
+
if m.channel.job_thread_alive?
|
83
|
+
restart!(m)
|
84
|
+
true
|
85
|
+
else
|
86
|
+
false
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def restart!(m)
|
91
|
+
stop(m) if m.channel.job_thread_alive?
|
92
|
+
start(m)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Cinch
|
2
|
+
module Plugins
|
3
|
+
class Octospy
|
4
|
+
module Recording
|
5
|
+
def self.included(base)
|
6
|
+
base.class_eval do
|
7
|
+
match(/watch ([\w\-\.]+)\/([\w\-\.]+)/, method: :watch_repository)
|
8
|
+
match(/unwatch ([\w\-\.]+)\/([\w\-\.]+)/, method: :unwatch_repository)
|
9
|
+
match(/watch ([\w\-\.]+)/, method: :watch_repositories)
|
10
|
+
match(/unwatch ([\w\-\.]+)/, method: :unwatch_repositories)
|
11
|
+
match(/show watched( repos(itories)?)?/, method: :show_watched_repositories)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def watch_repository(m, owner, project)
|
16
|
+
repo = "#{owner}/#{project}"
|
17
|
+
|
18
|
+
unless ::Octokit.repository?(repo)
|
19
|
+
m.reply "Sorry, '#{repo}' not found"
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
::Octospy.add_channel m.channel.name
|
24
|
+
::Octospy.channel(m.channel.name).add_repo(repo)
|
25
|
+
|
26
|
+
restart(m)
|
27
|
+
m.reply "I started to watch the #{repo} events"
|
28
|
+
end
|
29
|
+
|
30
|
+
def watch_repositories(m, owner)
|
31
|
+
user = ::Octokit.user?(owner)
|
32
|
+
|
33
|
+
unless user
|
34
|
+
m.reply "Sorry, '#{owner}' not found"
|
35
|
+
return
|
36
|
+
end
|
37
|
+
|
38
|
+
::Octospy.add_channel m.channel.name
|
39
|
+
method = "#{'org_' if user.type == 'Organization'}repos".to_sym
|
40
|
+
repos = ::Octokit.send(method, owner).map { |repo|
|
41
|
+
::Octospy.channel(m.channel.name).add_repo(repo.full_name)
|
42
|
+
repo.full_name
|
43
|
+
}
|
44
|
+
|
45
|
+
if repos.count > 0
|
46
|
+
m.reply "I started to watch events of #{repos.count} repositories"
|
47
|
+
restart(m)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def unwatch_repository(m, owner, project)
|
52
|
+
repo = "#{owner}/#{project}"
|
53
|
+
|
54
|
+
unless ::Octokit.repository?(repo)
|
55
|
+
m.reply "Sorry, '#{repo}' not found"
|
56
|
+
return
|
57
|
+
end
|
58
|
+
|
59
|
+
::Octospy.channel(m.channel.name).remove_repo(repo)
|
60
|
+
|
61
|
+
restart(m)
|
62
|
+
m.reply "I stopped to watch the #{repo} events"
|
63
|
+
end
|
64
|
+
|
65
|
+
def unwatch_repositories(m, owner)
|
66
|
+
repos = ::Octospy.channel(m.channel.name).repos.each_with_object([]) do |repo, obj|
|
67
|
+
next unless repo.split('/').first == owner
|
68
|
+
::Octospy.channel(m.channel.name).remove_repo(repo)
|
69
|
+
opj << repo
|
70
|
+
end
|
71
|
+
|
72
|
+
if repos.count > 0
|
73
|
+
if ::Octospy.channel(m.channel.name).repos.count > 0
|
74
|
+
m.reply "stopped to watch events of #{repos.count} repositories"
|
75
|
+
restart(m)
|
76
|
+
else
|
77
|
+
m.reply "stopped job so no watched repository"
|
78
|
+
stop(m)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def unwatch_all(m)
|
84
|
+
end
|
85
|
+
|
86
|
+
def show_watched_repositories(m)
|
87
|
+
channel = ::Octospy.channel(m.channel.name)
|
88
|
+
|
89
|
+
if channel.nil? || channel.repos.nil? || !channel.repos
|
90
|
+
m.reply 'nothing!'
|
91
|
+
return
|
92
|
+
end
|
93
|
+
|
94
|
+
channel.repos.each.with_index(1) do |repo, i|
|
95
|
+
m.reply "#{i} #{repo}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'cinch/plugins/octospy/recording'
|
2
|
+
require 'cinch/plugins/octospy/job'
|
3
|
+
|
4
|
+
module Cinch
|
5
|
+
module Plugins
|
6
|
+
class Octospy
|
7
|
+
include Cinch::Plugin
|
8
|
+
include Octospy::Recording
|
9
|
+
include Octospy::Job
|
10
|
+
|
11
|
+
set :prefix, ->(m) { %r(^#{Regexp.escape "#{m.bot.nick}: "}) }
|
12
|
+
|
13
|
+
match(/hello|hi|hey/, method: :greet)
|
14
|
+
match('ping', method: :pong)
|
15
|
+
match('rename', method: :rename)
|
16
|
+
match(/join (.+)/, method: :join)
|
17
|
+
match(/part(?: (.+))?/, method: :part)
|
18
|
+
match(/show status/, method: :show_status)
|
19
|
+
match(/show commands/, method: :show_commands)
|
20
|
+
|
21
|
+
listen_to :invite, method: :join_on_invite
|
22
|
+
|
23
|
+
def greet(m)
|
24
|
+
m.reply "hi #{m.user.nick}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def pong(m)
|
28
|
+
m.reply "#{m.user.nick}: pong"
|
29
|
+
end
|
30
|
+
|
31
|
+
def rename(m)
|
32
|
+
@bot.nick += '_'
|
33
|
+
end
|
34
|
+
|
35
|
+
def join(m, channel)
|
36
|
+
ch = "##{channel.gsub('#', '')}"
|
37
|
+
Channel(ch).join
|
38
|
+
m.reply "#{ch} joined!"
|
39
|
+
end
|
40
|
+
|
41
|
+
def part(m, channel)
|
42
|
+
channel ||= m.channel
|
43
|
+
if channel
|
44
|
+
ch = "##{channel.gsub('#', '')}"
|
45
|
+
Channel(ch).part
|
46
|
+
m.reply "#{ch} parted!" unless ch == m.channel
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def show_status(m)
|
51
|
+
@bot.channels.each.with_index(1) do |channel, i|
|
52
|
+
number = ::Octospy.channel(channel).repos.count
|
53
|
+
m.reply "#{"%02d" % i} #{channel}: #{number} repo"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def show_commands(m)
|
58
|
+
# @matchers.each.with_index(1) do |matcher, i|
|
59
|
+
# m.reply "#{"%02d" % i} #{matcher}"
|
60
|
+
# end
|
61
|
+
end
|
62
|
+
|
63
|
+
def join_on_invite(m)
|
64
|
+
Channel(m.channel).join
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Octospy
|
2
|
+
module Configurable
|
3
|
+
OPTIONS_KEYS = %i(
|
4
|
+
channels
|
5
|
+
server
|
6
|
+
nick
|
7
|
+
github_api_endpoint
|
8
|
+
github_web_endpoint
|
9
|
+
github_login
|
10
|
+
github_token
|
11
|
+
).freeze
|
12
|
+
|
13
|
+
attr_accessor(*OPTIONS_KEYS)
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def keys
|
17
|
+
@keys ||= OPTIONS_KEYS
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
DEFAULT_GITHUB_API_ENDPOINT = ENV['GITHUB_API_ENDPOINT'] || 'https://api.github.com'
|
22
|
+
DEFAULT_GITHUB_WEB_ENDPOINT = ENV['GITHUB_WEB_ENDPOINT'] || 'https://github.com'
|
23
|
+
DEFAULT_NICK = ENV['NICK'] || 'octospy'
|
24
|
+
|
25
|
+
def configure
|
26
|
+
yield self
|
27
|
+
end
|
28
|
+
|
29
|
+
def options
|
30
|
+
Hash[Octospy::Configurable.keys.map{ |key|
|
31
|
+
[key, instance_variable_get(:"@#{key}")]
|
32
|
+
}]
|
33
|
+
end
|
34
|
+
|
35
|
+
def setup
|
36
|
+
@github_api_endpoint = DEFAULT_GITHUB_API_ENDPOINT
|
37
|
+
@github_web_endpoint = DEFAULT_GITHUB_WEB_ENDPOINT
|
38
|
+
@nick = DEFAULT_NICK
|
39
|
+
@channels = if ENV['CHANNELS']
|
40
|
+
ENV['CHANNELS'].gsub(/\s|#/, '').split(',').map { |ch| "##{ch}" }
|
41
|
+
else
|
42
|
+
''
|
43
|
+
end
|
44
|
+
@server = ENV['SERVER']
|
45
|
+
@github_login = ENV['GITHUB_LOGIN']
|
46
|
+
@github_token = ENV['GITHUB_TOKEN']
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'string-irc'
|
2
|
+
require 'octospy/shortener'
|
3
|
+
|
4
|
+
module Octospy
|
5
|
+
module Extensions
|
6
|
+
module String
|
7
|
+
def underscore
|
8
|
+
self.gsub('::', '/').
|
9
|
+
gsub(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2').
|
10
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
11
|
+
tr("-", "_").
|
12
|
+
downcase
|
13
|
+
end
|
14
|
+
|
15
|
+
def split_by_linefeed_except_blankline
|
16
|
+
self.split(/\r\n|\n/).map { |v| v unless v.eql? '' }.compact
|
17
|
+
end
|
18
|
+
alias_method :split_lfbl, :split_by_linefeed_except_blankline
|
19
|
+
|
20
|
+
def colorize_for_irc
|
21
|
+
StringIrc.new(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
def shorten_url
|
25
|
+
case
|
26
|
+
when self =~ /https?:\/\/(\w+\.)?github\.com/
|
27
|
+
Octospy::Shortener.shorten_by_github self
|
28
|
+
when self =~ /https?:\/\/.+/
|
29
|
+
Octospy::Shortener.shorten_by_google self
|
30
|
+
else
|
31
|
+
self
|
32
|
+
end
|
33
|
+
end
|
34
|
+
alias_method :shorten, :shorten_url
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
::String.__send__ :include, Octospy::Extensions::String
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Octospy
|
2
|
+
class Parser
|
3
|
+
module Gist
|
4
|
+
def parse_gist_event
|
5
|
+
unless @event.payload.gist.description.eql? ''
|
6
|
+
title = @event.payload.gist.description
|
7
|
+
else
|
8
|
+
title = ''
|
9
|
+
end
|
10
|
+
|
11
|
+
{
|
12
|
+
status: "#{@event.payload.action}d gist",
|
13
|
+
title: title,
|
14
|
+
link: @event.payload.gist.html_url,
|
15
|
+
none_repository: true
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Octospy
|
2
|
+
class Parser
|
3
|
+
module Issue
|
4
|
+
def parse_issues_event
|
5
|
+
body = "#{@event.payload.issue.body}".split_lfbl
|
6
|
+
|
7
|
+
if @event.payload.issue.assignee
|
8
|
+
body << "assignee: #{@event.payload.issue.assignee.login}"
|
9
|
+
end
|
10
|
+
|
11
|
+
if @event.payload.issue.milestone
|
12
|
+
milestone_title = @event.payload.issue.milestone.title
|
13
|
+
milestone_state = @event.payload.issue.milestone.state
|
14
|
+
body << "milestone: #{milestone_title}[#{milestone_state}]"
|
15
|
+
end
|
16
|
+
|
17
|
+
{
|
18
|
+
status: "#{@event.payload.action} issue ##{@event.payload.issue.number}",
|
19
|
+
title: @event.payload.issue.title,
|
20
|
+
body: body,
|
21
|
+
link: @event.payload.issue.html_url
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse_issue_comment_event
|
26
|
+
if @event.payload.action == 'created'
|
27
|
+
status = "commented on issue ##{@event.payload.issue.number}"
|
28
|
+
title = @event.payload.issue.title
|
29
|
+
else
|
30
|
+
status = "#{@event.payload.action} issue comment"
|
31
|
+
title = ''
|
32
|
+
end
|
33
|
+
|
34
|
+
{
|
35
|
+
status: status,
|
36
|
+
title: title,
|
37
|
+
body: "#{@event.payload.comment.body}".split_lfbl,
|
38
|
+
link: @event.payload.comment.html_url
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|