october 0.1.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.
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