GithubHelp home page GithubHelp logo

skellington-closet / skellington Goto Github PK

View Code? Open in Web Editor NEW
64.0 2.0 6.0 3.59 MB

:sparkles::skull::sparkles: The skeleton for your bots

License: MIT License

JavaScript 100.00%
slack-bots botkit slack

skellington's Introduction

Skellington: the logo is jack the chat bubble, get it???

Build Status Coverage Status Standard - JavaScript Style Guide Greenkeeper badge

The skeleton for your Slack bots.

Composable Slack Bots

Skellington is a skeleton for your Botkit Slack bots. It handles the boilerplate connection and error handling and let's you get down to the business of bot-making. You can write a new bot in just a few of lines of code!

Skellington has a robust plugin architecture letting you import plugins into your Skellington bot to mix and match functionality. This will let you keep your bot small, code clean, and your deployments simple.

Usage

This is all the code you need to write to make a Skellington bot for a single team:

require('skellington')({
  slackToken: 'xoxb-abc123-def-456',
  plugins: [require('gobot'), require('awesom-o')]  
});

Creating a Slack App

You can also use Skellington to set up a Slack app for incoming webhooks, slash commands, and multiteam support. Just pass a few configs:

require('skellington')({
  clientId: 'jack',
  clientSecret: 'shhhhhh',
  port: 433,
  scopes: ['bot'], // optional, scopes can come from the config or from plugins
  state: 'kentucky', // optional state passed back during the OAuth authentication flow
  redirectUri: 'http://skellington.is.cool', // optional redirect URI configured in Slack for your app
  plugins: [require('gobot'), require('awesom-o')]  
});

OAuth and slash command endpoints will be created for you. The oauth path will be /oauth and the slash command endpoint will be /slack/receive.

If required configs are missing, Skellington will exit with a helpful error message to get you up and running.

Built-in Help Commands

Want to know what commands your bot supports? Direct mention (@bot help) or direct message your bot help and your bot will give you a list of help topics. Each plugin you register with your bot can add it's own help commands.

Skellington Config Options

Skellington will allow you to create a single team bot for that team or a Slack app capable of multi-team bots, slash commands, and incoming webhooks. These types are mutually exclusive and which type you create depends on the options you pass.

  • botkit (Object) An optional object of options passed directly to Botkit.slackbot.

  • logger (Object) A custom logger, defaults to Skellington's internal logging. Logger must implement debug, info, and error methods.

  • plugins (Array, Required) An array of plugins. See below for details.

  • port (Number, Required for Slack App) If passed, will create an express server listening on the port. The express app will be passed to plugins in the init callback. The paths /oauth and /slack/receive are reserved.

  • debug (Boolean) Whether to turn on debug mode. By default this value will be used for the botkit.debug option, but this can be overridden in the botkit config.

  • debugOptions (Object) Used if debug is true.

    • debugOptions.formatter (Function) A formatter function that will be used to log any message to a hears call. Will be passed the message object. Additional debug information will be added onto the message on the skellington key.

Single Team Bot Options

  • slackToken (String, Required) If this is a single team bot, the Slack API token used to connect to the Slack API. When slackToken is passed, Skellington will create a single team bot. Otherwise Skellington will attempt to build a Slack app.

  • exitOnRtmFailure (Boolean) Whether to exit the process if an RTM connection cannot be established. Defaults to true.

Slack App Options

  • clientId (String, Required) Your Slack OAuth client ID.

  • clientSecret (String, Required) Your Slack OAuth client secret.

  • redirectUri (String) A redirect URI to pass to Slack during the OAuth flow. If passed, Slack will redirect to this URI therefore it should be the Skellington host. To redirect from Skellington after the OAuth flow is complete, use successRedirectUri and errorRedirectUri.

  • state (String) State that will be returned from Slack as part of the OAuth flow. This is usually used to verify the callback from the Identity Provider (Slack, in this case) is legitimate.

  • scopes (Array) The OAuth scopes your app will be requesting. Defaults to no scopes. Scopes can be passed from plugins as well.

  • startRtm (Boolean) Defaults to true. If strictly false Skellington will not initiate an RTM connection when adding a new bot. Setting startRtm false is good for Slack apps that will rely solely on the Events API for events. NOTE: When startRtm is false the botConnected lifecycle method will never be called.

  • successRedirectUri (String) A URI to for Skellington to redirect to after a successful OAuth authentication flow.

  • errorRedirectUri (String) A URI to for Skellington to redirect to after a failed OAuth authentication flow.

Botkit Versions

Botkit is a core dependency of Skellington and is caret matched in package.json. This means that any bug fixes (patch releases) and new features (minor releases) in Botkit will be automatically picked up each time you install Skellington. This is a bet on semver which the Botkit project has appeared to follow well.

Note: Botkit is currently in 0.X.Y versioning, so a ^ match will only pick up "patch" releases.

When/if Botkit publishes a breaking change, I will file a Skellington issue to track it and for the community to comment on. The subsequent Skellington version bump will either be a minor or major release, depending on the impact.

If you find an issue related to a Botkit version picked up by Skellington, please file an issue.

Tips on Managing the Botkit Dependency

  • Shrinkwrap your bot, this will give you consistency from build to build.
  • Test your bot before you deploy to production. Fire it up and click around and look for anything weird (don't forget to check your logs).
  • If you run into an issue due to a Botkit bug, try downgrading Botkit:
    • cd node_modules/skellington && npm install botkit@<version> && cd ../..
    • If this solves the issue, shrinkwrap your bot and please file an issue.

Plugin API

init

  • init(controller, bot, expressApp)

Each plugin passed to Skellington can export an object with an init function that will take a botkit controller, bot, and optionally an Express app (this will only exist if config.port was set). This callback will be called once when Skellington is started. This is when most plugins will set up their listeners for Slack and Botkit events. Learn more about the Botkit API in the howdyai/botkit docs.

NOTE: the bot parameter will be null for Slack Apps, since init is called only once before any teams have connected. If you want access to the team bot, you can write a botConnected callback that will be called whenever a new team initiates an RTM session with Slack.

module.exports = {
  init: function(controller, bot, expressApp) {
    // build your bot logic here!
    controller.hears('hello', 'direct_mention', function(bot, message) {
      bot.reply(message, 'Hi!');
    });  
  }
};

botConnected

  • botConnected(controller, bot)

The botConnected callback is called any time a bot connects to an RTM session with Slack and is passed a reference to the controller and the bot. botConnected can be used for building a cache of team specific entities (like channels or users) or gather whatever information about a team you could need.

botConnected is called for single team bots and Slack apps, though for single team bots it is called at the same moment in the lifecycle as init. If startRtm is false for a Slack app then this lifecycle method will never be called.

It is only fired if the RTM session can be established unlike the Botkit create_bot event, which is called after a successful OAuth authorization flow, but before an RTM session is established.

module.exports = {
  botConnected: function(controller, bot) {
    // do some interesting things with the connected bot!  
  }
};

scopes

  • Array

For plugins that are for Slack apps you can pass an array of OAuth scopes your plugin will require.

module.exports = {
  init: function(controller, bot, expressApp) {
    // what an awesome multi-team bot!  
  },
  scopes: ['bot']
};

help

  • Object

You can optionally include help text for your plugin. This is a great way for To do this, you will need a a help object with command and text properties on your exported object. As in life, help is optional, but it does make things easier.

  • command (String, required) The command the user will use to get help about your plugin. For example if command is funny gifs, users will get help by typing @bot help funny gifs.

  • text (String or function, required) Either a string or a function. The string will be displayed as is. If text if a function, it will be passed an options object with the following properties:

Property Description
botName The user facing name of the bot. Useful if you have commands that require @-mentioning the bot.
team The team ID the help message came from.
channel The channel ID the help message came from.
user The ID of the user who initiated the help message.
// basic help
module.exports = {
  init: function(controller, bot, expressApp) {
    // initialize plugin
  },
  help: {
    command: 'funny gifs',
    text: 'They are so funny!'
  }
}

// advanced formatting
module.exports = {
  init: function(controller, bot, expressApp) {
    // initialize plugin
  },
  help: {
    command: 'funny gifs',
    text: function(opts) {
      return `${opts.botName} ${opts.team} ${opts.channel} ${opts.user}`
    }
  }
};

Considerations When Building a Plugin

Plan for Multiple Teams and Multiple Bots

Your plugin could be part of a Slack app or a single team bot. Users can also be running multiple Skellington bots within the same process, see the functional tests for an example. If possible, build your plugin to be stateless, but if you need to build a data store make sure to key it by team ID and/or bot ID.

Be Considerate With Data

Assume there will be several other plugins running in the same Skellington instance, so be considerate when you put things into the shared storage. Namespace any data specific to your plugin and don't modify things you didn't set.

When you read from storage, remember to always merge your updates with what was present in storage before. Here's an example of how to do that using lodash's merge method:

var myTeamData = {funnyGifs: 'some data'};
controller.storage.teams.get('teamId', function(err, team) {
  var mergedData = _.merge({id: 'teamId'}, team, myTeamData);
  controller.storage.teams.save(mergedData, function(err) {
    console.log('data updated!')
  })
})

Namespace Express Paths

If you are adding additional routes to the express app use a namespaced path, like /funny-gifs/endpoint. Don't add things to the root path, those are likely to conflict with another bot. The paths /oauth and /slack/receive are reserved.

skellington's People

Contributors

colestrode avatar greenkeeper[bot] avatar greenkeeperio-bot avatar jasonrhodes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

skellington's Issues

An in-range update of sinon-chai is breaking the build 🚨

The devDependency sinon-chai was updated from 3.3.0 to 3.4.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

sinon-chai is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push: The Travis CI build failed (Details).
  • coverage/coveralls: First build on greenkeeper/sinon-chai-3.4.0 at 100.0% (Details).

Release Notes for 3.4.0

https://github.com/domenic/sinon-chai/blob/master/CHANGELOG.md#340

Commits

The new version differs by 4 commits.

  • 942504a Fix trailing comma in package.json
  • d990858 3.4.0
  • 60df918 chore(infra): upgrade all deps (#144)
  • fb4f82a Docs: install sinon-chai as a dev dependency (#135)

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Add redirect after OAuth flow

The 200 and 500 OAuth flow just return JSON. Users should be able to define a success redirect and failure redirect in config.

Version 10 of node.js has been released

Version 10 of Node.js (code name Dubnium) has been released! 🎊

To see what happens to your code in Node.js 10, Greenkeeper has created a branch with the following changes:

  • Added the new Node.js version to your .travis.yml

If you’re interested in upgrading this repo to Node.js 10, you can open a PR with these changes. Please note that this issue is just intended as a friendly reminder and the PR as a possible starting point for getting your code running on Node.js 10.

More information on this issue

Greenkeeper has checked the engines key in any package.json file, the .nvmrc file, and the .travis.yml file, if present.

  • engines was only updated if it defined a single version, not a range.
  • .nvmrc was updated to Node.js 10
  • .travis.yml was only changed if there was a root-level node_js that didn’t already include Node.js 10, such as node or lts/*. In this case, the new version was appended to the list. We didn’t touch job or matrix configurations because these tend to be quite specific and complex, and it’s difficult to infer what the intentions were.

For many simpler .travis.yml configurations, this PR should suffice as-is, but depending on what you’re doing it may require additional work or may not be applicable at all. We’re also aware that you may have good reasons to not update to Node.js 10, which is why this was sent as an issue and not a pull request. Feel free to delete it without comment, I’m a humble robot and won’t feel rejected 🤖


FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Change config structure

Right now Skellington and botkit configs are mixed together in the same flattened config structure. I think we should break out the botkit specific configs into their own stanza, something like:

{
  "slackToken": "xob-abc-123",
  "plugins": [...],
  "botkit": {
    //botkit specific configs go here
  }
}

This will simplify the logic of passing configs to botkit and prevents collisions from future config options. It leaves the door open for different implementations in the future.

@jasonrhodes had a thought to make the key dynamic using a botType option:

{
  "botType": "botkit", // default to botkit
  "botkit": { ... botkit configs ... }
}

This will make it easy to switch config types in the future and support different underlying implementations.

Something to consider: whatever the underlying implementation it would be great to make sure the plugin API stays in tact. Not sure that's possible if we switch out the underlying implementation. We will probably need an adapter layer... but that's a discussion for another day.

Call startTicking if startRtm is false

From the Botkit docs:

Note: If you are not also establishing an RTM connection, you will need to manually run the controller.startTicking() method for conversations to work properly.

We need to call controller.startTicking if we are not establishing an RTM connection.

RTM connections timeout and don't restart

I've observed this on single-team bots, but I'm sure this would affect Slack apps as well. After some time, the RTM connection times out, I believe because the pong response doesn't come back after a timeout. This is the error logged:

Error: Stale RTM connection, closing RTM
    at Timeout.pinger [as _onTimeout] (/Users/cfurfarostrode/src/projects/pizza-bot/node_modules/botkit/lib/Slackbot_worker.js:182:35)
    at ontimeout (timers.js:365:14)
    at tryOnTimeout (timers.js:237:5)
    at Timer.listOnTimeout (timers.js:207:5)

It would be good to catch that error and try to reconnect. If we can't reconnect, exit (if single team bot and option is set) or at the very least log something out in the logs. It would be good to include any team information we have, though we might not have any in that error.

Changelog

Need to start a changelog, at least starting in 1.0.

Look into ways to automate this using commit history.

Botkit dependency matching

Botkit is a critical dependency of Skellington. I have two competing concerns: one that skellington remain stable and two that users not have to wait for new features in Botkit.

I've locked down the Botkit version because of the first concern. But I've also hooked up greenkeeper to this repo to address the second.

This approach definitely favors stability. However the drawback is that a new version of Botkit will require a new version of Skellington. This seems like it will create unnecessary work all around.

I'm thinking "betting on semver" and changing to a ^ match on the Botkit dep. ^ matches will allow propagate new features and prevent breaking changes from being pulled in. Botkit is currently in 0.X.X version, so caret match will pick up "patch" changes only (which are equivalent to minor version bumps of a 1.0.0 or greater package). So far, I believe Botkit has followed semver well. If it looks like they don't follow it, I will go back to a locked version.

To satisfy my want for stability, I'll document how to lock down deps (shrinkwrap) and how to lock in a specific version of botkit in case of a breaking change (roughly cd node_modules/skellington && npm install -S botkit@version && cd - && npm shrinkwrap)

Add a debug mode

On debug, log out each message to hears callbacks (maybe the on callback?) and allow configurable log formatter.

Attach "interesting" debug information to the message (i.e., the calling file to track down a weird plugin).

debug = true at the skellington level, should set debug = true at the botkit level, unless there is an explicit override for botkit = false.

Add greenkeeper

Keep deps up to date with greenkeeper. Do a patch bump when dependencies change. Merge in dev-deps when they change, but don't change skellington version.

An in-range update of coveralls is breaking the build 🚨

The devDependency coveralls was updated from 3.0.7 to 3.0.8.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

coveralls is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push: The Travis CI build failed (Details).
  • coverage/coveralls: First build on greenkeeper/coveralls-3.0.8 at 100.0% (Details).

Commits

The new version differs by 24 commits.

There are 24 commits in total.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Refactor

It's about that time... maybe something like this?

lib/singleBot (sets up a single team bot)
lib/slackApp (sets up a slack app)
lib/config (manages config)
lib/help (registers help listeners)
lib/server (starts webserver, etc)
lib/lifecycle (initializes plugins, botConnected)

json_file_store

This doesn't seem to work, as it doesn't appear you are passing all config from the skellington constructor into the botkit constructor

An in-range update of botkit is breaking the build 🚨

The dependency botkit was updated from 0.6.18 to 0.6.19.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

botkit is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • continuous-integration/travis-ci/push: The Travis CI build could not complete due to an error (Details).
  • coverage/coveralls: First build on greenkeeper/botkit-0.6.19 at 100.0% (Details).

Commits

The new version differs by 16 commits.

  • b6dfcf3 List updates in changelog
  • 7cb60ca updated package-lock
  • 9ff7dc0 Merge branch 'npmaudit'
  • b46f593 Merge branch 'master' of github.com:howdyai/botkit
  • 2334145 remove deprecated example
  • f1c6101 Update readme.md
  • 7604031 Update readme.md
  • 3f33568 Merge pull request #1498 from akalsey/master
  • edad8eb rebrand Webex in readme
  • 6c42613 remove dependency on promise lib
  • 55bc7f4 update all deps to latest
  • 55830e2 updated cli
  • 37e0ea4 pdated cli removes dependence on vorpal
  • b2a7b46 Apply more stringent linter rules
  • b96c4aa eslint autofix problems

There are 16 commits in total.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Integration Tests

Now that greenkeeper is wired up, it would be great to have some integration tests to protect against breaking changes in the interface of a dep.

One possible strategy would be to have a staging environment and use the Slack API to post messages. We could have a test "echo" plugin that just echos back what it hears in a channel. We could then inspect channel history to ensure the plugins connected successfully and was able to post.

I'm not sure how to integration test inviting a bot to a team, I'm not sure there is an API for that.

Stop being so helpful with the RTM already

Skellington adds an rtm_close listener to reconnect to the RTM session if there was an error. This is problematic for two reasons:

  1. Sometimes the RTM session can be closed intentionally and we are not checking for that
  2. Botkit has it's own reconnection strategy, this causes the RTM connection to be re-established twice, resulting in double messages/responses.

We should remove the rtm_close handler and defer the reconnection to Botkit.

Support different Bot Engines

It would be great to support other engines. The first I'd like to look at is Slapp.

There are a lot of details to flesh out, and this would most certainly be a major release. This ticket is a placeholder, more details to come.

What would be ideal is for Skellington to have it's own Engine interface and then we could write different engine modules (e.g., skellington-engine-botkit, skellington-engine-slapp). This would keep Skellington from growing unwieldy and also allow others to write their own engines if they want. This may be a pie in the sky dream... but 🤞

I think the plugin API should support a "type" or "engine" field. If absent, it will default to "botkit" for backwards compatibility. Plugins whose type doesn't match the engine will not be loaded and an error should be logged.

An in-range update of proxyquire is breaking the build 🚨

The devDependency proxyquire was updated from 2.1.2 to 2.1.3.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

proxyquire is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push: The Travis CI build failed (Details).

Commits

The new version differs by 2 commits.

  • aaae296 2.1.3
  • 6a01bc1 fix: throw correct error when simulating MODULE_NOT_FOUND (#246)

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of sinon is breaking the build 🚨

Version 2.4.0 of sinon just got published.

Branch Build failing 🚨
Dependency sinon
Current Version 2.3.8
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

As sinon is “only” a devDependency of this project it might not break production or downstream projects, but “only” your build or test tools – preventing new deploys or publishes.

I recommend you give this issue a high priority. I’m sure you can resolve this 💪

Status Details
  • coverage/coveralls First build on greenkeeper/sinon-2.4.0 at 100.0% Details
  • continuous-integration/travis-ci/push The Travis CI build failed Details

Commits

The new version differs by 11 commits.

  • 20eb865 Update docs/changelog.md and set new release id in docs/_config.yml
  • e333e75 Add release documentation for v2.4.0
  • fde7911 2.4.0
  • 9afdcfc Update Changelog.txt and AUTHORS for new release
  • 57bb8b3 Merge pull request #1489 from Rowno/named-anonymous-mocks
  • c9a35ef Update fake-xhr-and-server.md
  • 837ec0c Allow anonymous mock functions to be named
  • 259a330 Merge pull request #1481 from fatso83/fix-safari-breaking
  • e742268 Merge pull request #1488 from VynceMontgomery/patch-1
  • a6a2b8c Clarify behavior of useFakeTimers
  • 24d15f2 Avoid running test for #1456 on Safari

See the full diff

Not sure how things should work exactly?

There is a collection of frequently asked questions and of course you may always ask my humans.


Your Greenkeeper Bot 🌴

Better logging

Use something like skellington-logger to distinguish between botkit logs and skellington logs and to print a better format.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.