Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
technicalpickles committed Oct 18, 2014
0 parents commit 9335e48
Show file tree
Hide file tree
Showing 11 changed files with 299 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .editorconfig
@@ -0,0 +1,12 @@
# http://editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
1 change: 1 addition & 0 deletions .gitignore
@@ -0,0 +1 @@
node_modules
6 changes: 6 additions & 0 deletions .travis.yml
@@ -0,0 +1,6 @@
language: node_js
node_js:
- "0.11"
- "0.10"
notifications:
email: false
40 changes: 40 additions & 0 deletions Gruntfile.js
@@ -0,0 +1,40 @@
'use strict';

module.exports = function(grunt) {

grunt.loadNpmTasks('grunt-mocha-test');
grunt.loadNpmTasks('grunt-release');

grunt.initConfig({
mochaTest: {
test: {
options: {
reporter: 'spec',
require: 'coffee-script'
},
src: ['test/**/*.coffee']
}
},
release: {
options: {
tagName: 'v<%= version %>',
commitMessage: 'Prepared to release <%= version %>.'
}
},
watch: {
files: ['Gruntfile.js', 'test/**/*.coffee'],
tasks: ['test']
}
});

grunt.event.on('watch', function(action, filepath, target) {
grunt.log.writeln(target + ': ' + filepath + ' has ' + action);
});

// load all grunt tasks
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

grunt.registerTask('test', ['mochaTest']);
grunt.registerTask('test:watch', ['watch']);
grunt.registerTask('default', ['test']);
};
63 changes: 63 additions & 0 deletions README.md
@@ -0,0 +1,63 @@
# hubot-redis-brain

A hubot script to persist hubot's brain using redis

See [`src/redis-brain.coffee`](src/redis-brain.coffee) for full documentation.

## Installation

In hubot project repo, run:

`npm install hubot-redis-brain --save`

Then add **hubot-redis-brain** to your `external-scripts.json`:

```json
[
"hubot-redis-brain"
]
```

## Configuration

hubot-redis-brain requires a redis server to work. It uses the `REDIS_URL` environment variable for determining
where to connect to. The default is on localhost, port 6379 (ie the redis default).

The following attributes can be set using the `REDIS_URL`

* authentication
* hostname
* port
* key prefix

For example, `export REDIS_URL=redis://passwd@192.168.0.1:16379/prefix` would
authenticate with `password`, connecting to 192.168.0.1 on port 16379, and store
data using the `prefix:storage` key.

### Installing your own

If you need to install and
run your own, most package managers have a package for redis:

* Mac OS X with homebrew: `brew install redis`
* Ubuntu/Debian with apt: `apt-get install redis-server`
* Compile from source: http://redis.io/topics/quickstart

### Boxen

If you are using [boxen](https://boxen.github.com/) to manage your enviromemnt,
hubot-redis-brain will automatically use the boxen-managed redis (ie by using `BOXEN_REDIS_URL`).


### Heroku

If you are deploying on [Heroku](https://www.heroku.com/), you can add the
Redis Cloud or Redis To Go addon to have automatically configure itself to use it:

* [Redis Cloud](https://addons.heroku.com/rediscloud)
* [Redis To Go](https://addons.heroku.com/redistogo)


Other redis addons would need to be configured using `REDIS_URL` until support
is added to hubot-redis-brain (or hubot-redis-brain needs to be updated to look
for the environment variable the service uses)
12 changes: 12 additions & 0 deletions index.coffee
@@ -0,0 +1,12 @@
fs = require 'fs'
path = require 'path'

module.exports = (robot, scripts) ->
scriptsPath = path.resolve(__dirname, 'src')
fs.exists scriptsPath, (exists) ->
if exists
for script in fs.readdirSync(scriptsPath)
if scripts? and '*' not in scripts
robot.loadFile(scriptsPath, script) if script in scripts
else
robot.loadFile(scriptsPath, script)
44 changes: 44 additions & 0 deletions package.json
@@ -0,0 +1,44 @@
{
"name": "hubot-redis-brain",
"description": "A hubot script to persist hubot's brain using redis",
"version": "0.0.0",
"author": "Josh Nichols <technicalpickles@github.com>",
"license": "MIT",

"keywords": "hubot, hubot-scripts",

"repository": {
"type": "git",
"url": "git://github.com/hubot-scripts/hubot-redis-brain.git"
},

"bugs": {
"url": "https://github.com/hubot-scripts/hubot-redis-brain/issues"
},

"dependencies": {
"redis": "0.8.4"
},

"peerDependencies": {
"hubot": "2.x"
},

"devDependencies": {
"hubot": "2.x",
"mocha": "*",
"chai": "*",
"sinon-chai": "*",
"sinon": "*",
"grunt-mocha-test": "~0.7.0",
"grunt-release": "~0.6.0",
"matchdep": "~0.1.2",
"grunt-contrib-watch": "~0.5.3"
},

"main": "index.coffee",

"scripts": {
"test": "grunt test"
}
}
18 changes: 18 additions & 0 deletions script/bootstrap
@@ -0,0 +1,18 @@
#!/bin/bash

# Make sure everything is development forever
export NODE_ENV=development

# Load environment specific environment variables
if [ -f .env ]; then
source .env
fi

if [ -f .env.${NODE_ENV} ]; then
source .env.${NODE_ENV}
fi

npm install

# Make sure coffee and mocha are on the path
export PATH="node_modules/.bin:$PATH"
6 changes: 6 additions & 0 deletions script/test
@@ -0,0 +1,6 @@
#!/bin/bash

# bootstrap environment
source script/bootstrap

mocha --compilers coffee:coffee-script
78 changes: 78 additions & 0 deletions src/redis-brain.coffee
@@ -0,0 +1,78 @@
# Description:
# Persist hubot's brain to redis
#
# Configuration:
# REDISTOGO_URL or REDISCLOUD_URL or BOXEN_REDIS_URL or REDIS_URL.
# URL format: redis://<host>:<port>[/<brain_prefix>]
# If not provided, '<brain_prefix>' will default to 'hubot'.
#
# Commands:
# None

Url = require "url"
Redis = require "redis"

module.exports = (robot) ->
redisUrl = if process.env.REDISTOGO_URL?
redisUrlEnv = "REDISTOGO_URL"
process.env.REDISTOGO_URL
else if process.env.REDISCLOUD_URL?
redisUrlEnv = "REDISCLOUD_URL"
process.env.REDISCLOUD_URL
else if process.env.BOXEN_REDIS_URL?
redisUrlEnv = "BOXEN_REDIS_URL"
process.env.BOXEN_REDIS_URL
else if process.env.REDIS_URL?
redisUrlEnv = "REDIS_URL"
process.env.REDIS_URL
else
'redis://localhost:6379'

if redisUrlEnv?
robot.logger.info "Discovered redis from #{redisUrlEnv} environment variable"
else
robot.logger.info "Using default redis on localhost:6379"


info = Url.parse redisUrl, true
client = Redis.createClient(info.port, info.hostname)
prefix = info.path?.replace('/', '') or 'hubot'

robot.brain.setAutoSave false

getData = ->
client.get "#{prefix}:storage", (err, reply) ->
if err
throw err
else if reply
robot.logger.info "Data for #{prefix} brain retrieved from Redis"
robot.brain.mergeData JSON.parse(reply.toString())
else
robot.logger.info "Initializing new data for #{prefix} brain"
robot.brain.mergeData {}

robot.brain.setAutoSave true

if info.auth
client.auth info.auth.split(":")[1], (err) ->
if err
robot.logger.error "Failed to authenticate to Redis"
else
robot.logger.info "Successfully authenticated to Redis"
getData()

client.on "error", (err) ->
if /ECONNREFUSED/.test err.message

else
robot.logger.error err.stack

client.on "connect", ->
robot.logger.debug "Successfully connected to Redis"
getData() if not info.auth

robot.brain.on 'save', (data = {}) ->
client.set "#{prefix}:storage", JSON.stringify data

robot.brain.on 'close', ->
client.quit()
19 changes: 19 additions & 0 deletions test/redis-brain-test.coffee
@@ -0,0 +1,19 @@
chai = require 'chai'
sinon = require 'sinon'
chai.use require 'sinon-chai'

expect = chai.expect

describe 'redis-brain', ->
beforeEach ->
@robot =
respond: sinon.spy()
hear: sinon.spy()

require('../src/redis-brain')(@robot)

it 'registers a respond listener', ->
expect(@robot.respond).to.have.been.calledWith(/hello/)

it 'registers a hear listener', ->
expect(@robot.hear).to.have.been.calledWith(/orly/)

0 comments on commit 9335e48

Please sign in to comment.