october 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/Gemfile +35 -0
  2. data/README.md +14 -0
  3. data/Rakefile +38 -0
  4. data/bin/october +8 -0
  5. data/boot.rb +5 -0
  6. data/config/database.yml.example +3 -0
  7. data/config/irc.yml.example +9 -0
  8. data/config/plugins.yml.example +2 -0
  9. data/config/redis.yml.example +7 -0
  10. data/lib/october.rb +16 -0
  11. data/lib/october/base.rb +28 -0
  12. data/lib/october/config.rb +23 -0
  13. data/lib/october/debugger.rb +51 -0
  14. data/lib/october/environment.rb +24 -0
  15. data/lib/october/plugin.rb +26 -0
  16. data/lib/october/plugin/help.rb +20 -0
  17. data/lib/october/plugins.rb +94 -0
  18. data/lib/october/redis.rb +20 -0
  19. data/lib/october/version.rb +3 -0
  20. data/lib/october/watchdog.rb +36 -0
  21. data/october.gemspec +25 -0
  22. data/plugins/.gitkeep +0 -0
  23. data/plugins/autossh.rb +23 -0
  24. data/plugins/fortune.rb +13 -0
  25. data/plugins/help.rb +11 -0
  26. data/plugins/hudson.rb +73 -0
  27. data/plugins/hudson/config.rb +41 -0
  28. data/plugins/hudson/fetcher.rb +40 -0
  29. data/plugins/hudson/reporter.rb +104 -0
  30. data/plugins/hudson/test_run.rb +88 -0
  31. data/plugins/issues.rb +161 -0
  32. data/plugins/joke.rb +32 -0
  33. data/plugins/links.rb +42 -0
  34. data/plugins/links/link.rb +68 -0
  35. data/plugins/service.rb +11 -0
  36. data/plugins/update.rb +79 -0
  37. data/plugins/whisper.rb +70 -0
  38. data/spec/fixtures/hudson/console.log +37 -0
  39. data/spec/helpers/bot_context.rb +5 -0
  40. data/spec/october/environment_spec.rb +28 -0
  41. data/spec/plugins/hudson/reporter_spec.rb +27 -0
  42. data/spec/plugins/hudson/test_run_spec.rb +17 -0
  43. data/spec/plugins/hudson_spec.rb +44 -0
  44. data/spec/plugins/issues_spec.rb +26 -0
  45. data/spec/plugins/links_spec.rb +16 -0
  46. data/spec/plugins/whisper_spec.rb +6 -0
  47. data/spec/spec_helper.rb +13 -0
  48. metadata +185 -0
data/Gemfile ADDED
@@ -0,0 +1,35 @@
1
+ source :rubygems
2
+
3
+ gem 'cinch'
4
+
5
+ gem 'rake', :require => false
6
+ gem 'activesupport', :require => 'active_support/core_ext'
7
+ gem 'i18n'
8
+
9
+ # debugging
10
+ group :development do
11
+ gem 'pry'
12
+ gem 'pry-nav'
13
+ gem 'awesome_print'
14
+ end
15
+
16
+ # Redis stuff
17
+ gem 'redis'
18
+ gem 'hiredis'
19
+ gem 'redis-namespace'
20
+ gem 'redis-objects', :require => 'redis/objects'
21
+
22
+ # http stuff
23
+ gem 'typhoeus'
24
+
25
+ # issues stuff - https://github.com/peter-murach/github/
26
+ gem 'github_api'
27
+
28
+ gem 'json'
29
+ gem 'nokogiri'
30
+ gem 'curb'
31
+
32
+ group :test do
33
+ gem 'rspec'
34
+ gem 'fakefs', :require => 'fakefs/safe'
35
+ end
@@ -0,0 +1,14 @@
1
+ # October
2
+ [![Build Status](https://secure.travis-ci.org/mikz/october.png)](http://travis-ci.org/#!/mikz/october)
3
+
4
+ IRC bot build on [Cinch framework](https://github.com/cinchrb/cinch) with some additional stuff like persistence layer od configuration in yml.
5
+
6
+ ## Plugins
7
+
8
+ October provides some sugar for regular Cinch plugins such as redis persistence and help command.
9
+
10
+
11
+ ## TODO
12
+
13
+ * Spec
14
+ * Moar features!
@@ -0,0 +1,38 @@
1
+ namespace :gem do
2
+ require "bundler/gem_tasks"
3
+ end
4
+
5
+ task :integrate do |task|
6
+ ENV['OCTOBER_ENV'] ||= 'test'
7
+ exec 'rspec spec'
8
+ end
9
+
10
+ task :environment, :env do |task, args|
11
+ ENV['OCTOBER_ENV'] ||= args[:env]
12
+
13
+ $:.unshift File.dirname(__FILE__)
14
+
15
+ require 'boot'
16
+ require 'october'
17
+
18
+ end
19
+
20
+ task :boot, [:env, :console] => :environment do |task, args|
21
+ @bot = October::Base.new
22
+ end
23
+
24
+ desc 'Starts IRC server'
25
+ task :start, [:env, :console] => :boot do |task, args|
26
+ if args[:console]
27
+ Cinch::IRC.send :include, October::Debugger
28
+ end
29
+
30
+ @bot.start
31
+ end
32
+
33
+ desc 'Creates interactive console with Pry'
34
+ task :console, [:env] => :boot do |task, args|
35
+ @bot.pry
36
+ end
37
+
38
+ #task :default => :start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path("..", File.dirname(__FILE__))
4
+
5
+ # this could be just 'october/daemon' when october will be rubygem
6
+ require File.expand_path(File.join('lib', 'october', 'watchdog'), root)
7
+
8
+ October::Watchdog.new(root, ARGV.shift).loop!
data/boot.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'bundler/setup'
2
+ Bundler.require *[:default, ENV['RACK_ENV'], ENV['OCTOBER_ENV']].compact
3
+
4
+ $:.unshift File.expand_path('lib')
5
+ $:.unshift File.expand_path('plugins')
@@ -0,0 +1,3 @@
1
+ 3scale:
2
+ adapter: sqlite3
3
+ database: db/3scale.sqlite3
@@ -0,0 +1,9 @@
1
+ 3scale:
2
+ server: irc.freenet.net
3
+ #port: 61669
4
+ channels:
5
+ - '#channel'
6
+ #password: 'yourpassword'
7
+ nick: 'nick'
8
+ ssl:
9
+ use: true
@@ -0,0 +1,2 @@
1
+ 3scale:
2
+ - hudson
@@ -0,0 +1,7 @@
1
+ default: &default
2
+ host: localhost
3
+
4
+ test:
5
+ <<: *default
6
+ namespace: test
7
+
@@ -0,0 +1,16 @@
1
+ require 'active_support/core_ext'
2
+
3
+ module October
4
+ autoload :Config, 'october/config'
5
+ autoload :Base, 'october/base'
6
+ autoload :Environment, 'october/environment'
7
+ autoload :Redis, 'october/redis'
8
+ autoload :Debugger, 'october/debugger'
9
+ autoload :Plugins, 'october/plugins'
10
+ autoload :Plugin, 'october/plugin'
11
+
12
+ def self.root
13
+ Pathname.new('.').expand_path
14
+ end
15
+ end
16
+
@@ -0,0 +1,28 @@
1
+ require 'cinch'
2
+
3
+ module October
4
+ class Base < Cinch::Bot
5
+
6
+ def self.start
7
+ new.start
8
+ end
9
+
10
+ include Config
11
+ include Redis
12
+ include Plugins.initialize
13
+
14
+ def initialize
15
+ super do
16
+ load_config!
17
+
18
+ on :message, "hello" do |m|
19
+ m.reply "Hello, #{m.user.nick}"
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end
28
+
@@ -0,0 +1,23 @@
1
+ module October
2
+ module Config
3
+ extend Environment
4
+ def load_config!
5
+ env = Config.configuration('irc.yml')
6
+ return unless env.present?
7
+
8
+ env.each_pair do |key, value|
9
+ # FIXME: make DRY
10
+ # FIXME: only one level - bad, only to support SSL nested values for now
11
+ if value.is_a? Hash
12
+ subconfig = config.send key.dup
13
+ value.each_pair do |key, value|
14
+ subconfig.send key.dup << '=', value
15
+ end
16
+ else
17
+ config.send key.dup << '=', value
18
+ end
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,51 @@
1
+ gem 'pry'
2
+
3
+ module October
4
+ module Debugger
5
+ extend ActiveSupport::Concern
6
+ ##
7
+ # Extends capabilities of Cinch::IRC to
8
+ # launch debugger after connecting and creating all threads
9
+ #
10
+
11
+ included do
12
+
13
+ self.class_eval do
14
+ if method_defined? :start
15
+ alias_pry(:start)
16
+ elsif method_defined? :connect
17
+ alias_pry(:connect)
18
+ else
19
+ raise 'Unsupported version of Cinch'
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ module InstanceMethods
26
+ def init_pry
27
+ Thread.new do
28
+ binding.pry
29
+ Thread.pass
30
+ end
31
+
32
+ end
33
+ end
34
+
35
+ module ClassMethods
36
+ def alias_pry(before)
37
+ class_eval %{
38
+
39
+ def #{before}_with_pry
40
+ init_pry
41
+ #{before}_without_pry
42
+ end
43
+
44
+ alias_method_chain :#{before}, :pry
45
+ }
46
+ end
47
+ end
48
+
49
+
50
+ end
51
+ end
@@ -0,0 +1,24 @@
1
+ module October
2
+ module Environment
3
+ class NoSuchEnvironment < StandardError; end
4
+
5
+ def load_configuration(file)
6
+ config = File.join('config', file)
7
+ return {} unless File.exists?(config)
8
+ YAML.load_file( config ).with_indifferent_access
9
+ end
10
+
11
+ def environment
12
+ ENV['OCTOBER_ENV'].presence || 'default'
13
+ end
14
+
15
+ def configuration(file, env = environment)
16
+ load_configuration(file)[env.to_sym]
17
+ end
18
+
19
+ def configuration!(file, env = environment)
20
+ configuration(file, env) or raise NoSuchEnvironment.new("No environment #{env} in file #{file}")
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ require 'active_support/concern'
2
+ require 'cinch'
3
+
4
+ module October
5
+ module Plugin
6
+ autoload :Help, 'october/plugin/help'
7
+
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ include Cinch::Plugin
12
+ extend Help
13
+ end
14
+
15
+ module ClassMethods
16
+ def name
17
+ to_s.underscore
18
+ end
19
+
20
+ def config
21
+ October::Plugins.config(name)
22
+ end
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,20 @@
1
+ module October
2
+ module Plugin
3
+ module Help
4
+ @@help = {}
5
+
6
+ def self.extended(base)
7
+ end
8
+
9
+ def register_help command, description = nil
10
+ @@help[command] = description
11
+ end
12
+
13
+ def list_help
14
+ @@help.map do |command, description|
15
+ [" !", [command, description].compact.join(' - ')].join
16
+ end.join("\n")
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,94 @@
1
+ module October
2
+ class Plugins < Array
3
+ extend Environment
4
+
5
+ attr_reader :loaded
6
+
7
+ def initialize
8
+ @loaded = []
9
+ import Plugins.configuration('plugins.yml')
10
+ end
11
+
12
+ delegate :registered, :configure, :to => :'self.class'
13
+
14
+ def import plugins
15
+ return unless plugins.present?
16
+
17
+ plugins = Hash[ plugins.map {|plugin|
18
+ plugin.respond_to?(:to_a) ? plugin.to_a.flatten(1) : [plugin, {}]
19
+ }].with_indifferent_access
20
+
21
+ names = plugins.keys.map {|name| name.camelize }
22
+
23
+ diff = registered.keys & (names - self)
24
+ push *diff
25
+ load diff
26
+
27
+ self.class.configure(plugins)
28
+ end
29
+
30
+ def imported
31
+ self
32
+ end
33
+
34
+
35
+ def load new
36
+ @loaded.push *new.map{ |plugin|
37
+ require registered[plugin]
38
+ plugin.constantize
39
+ }
40
+ end
41
+
42
+ module PluginMethods
43
+ extend ActiveSupport::Concern
44
+
45
+ included do
46
+ attr_reader :plugin_module
47
+ end
48
+
49
+ def initialize
50
+ plugins = Plugins.new
51
+ super
52
+ # stupid, really, why so long?
53
+ self.config.plugins.plugins.push *plugins.loaded
54
+ end
55
+
56
+ end
57
+
58
+ class << self
59
+
60
+ @@plugins = {}
61
+ @@configs = {}.with_indifferent_access
62
+
63
+ def initialize
64
+ October.root.join('plugins').
65
+ each_child(false).
66
+ each do |file|
67
+ next unless file.to_s =~ /\.rb$/
68
+ name = file.basename('.rb').to_s.camelize
69
+ register name => file
70
+ end
71
+
72
+ PluginMethods
73
+ end
74
+
75
+ def register plugin
76
+ @@plugins.merge! plugin
77
+ end
78
+
79
+ def config(plugin)
80
+ @@configs.fetch(plugin, {})
81
+ end
82
+
83
+ def configure(plugin)
84
+ @@configs.merge! plugin
85
+ end
86
+
87
+ def registered
88
+ @@plugins
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+ end
@@ -0,0 +1,20 @@
1
+ require 'redis'
2
+ require 'hiredis'
3
+ require 'active_support/core_ext/hash/keys'
4
+
5
+ module October
6
+ module Redis
7
+ extend Environment
8
+
9
+ def self.included(base)
10
+ return unless config = Redis.configuration('redis.yml')
11
+ # FIXME: parhaps more options, fetch from redis directly, or pass them all and let redis to handle it?
12
+ redis = ::Redis.new config.slice :host, :port, :path
13
+ if config.has_key? :namespace
14
+ redis = ::Redis::Namespace.new config[:namespace], :redis => redis
15
+ end
16
+ redis.incr 'launches'
17
+ $redis = redis
18
+ end
19
+ end
20
+ end