First class plugins are here!

October 24, 2020 by @devth

Since nearly the beginning of its existence, Yetibot has supported the notion of plugins by simply loading namespaces that looked like commands, e.g. mycompany.plugins.commands.mycommand, but it was up to the user to get the plugin JAR on the classpath or source file included in the local source tree.

This was never ideal, for a few reasons:

  • It meant the user needed to manage all the ops for their custom Yetibot, including building (JARs or Docker images) or figuring out a way to deploy from a source tree since the official JAR and Docker image were already baked.
  • The inconvenience prevented us from embracing a plugin ecosystem, instead baking everything into either yetibot or yetibot/core.

Usage

Configure the plugins you want to use, and Yetibot will resolve and load them on start up:

{:yetibot
 {:plugins
   {:kroki
     {:artifact "yetibot/kroki"
      :version "20201022.003832.0ae5bf7"}}}}

Beware that specifying a large number of plugins will increase Yetibot's start up time. This is the trade off between static (baking artifacts into an uberjar or Docker image) and dynamic (loading at runtime on startup).

Release automation

Yetibot's official plugins (those under the Yetibot GitHub Org) are ultra simple to create and release because of the surrounding automation we constructed:

  1. yetibot/parent uses lein-parent to specify common configuration across all Yetibot plugins (see yetibot-github's project.clj for an example of what this looks like).
  2. A new Leiningen plugin called lein-inferv allows us to infer versions rather than specify them in code, which allows us to avoid commit automation and noise to bump and snapshot versions. We already practiced this in yetibot/core using lein-git-version but the new plugin fully encodes our derived version schema and requires zero configuration.
  3. GitHub Organization workflows let us define how to release plugins in a single place that all future plugins can consume.

How to contribute a new module

If you have an idea for a module and think it should belong under the Yetibot org as an official plugin, feel free to suggest it in the #dev channel on Yetibot Slack.

Otherwise, anyone can build a module wherever they like, release it to an artifact repository and consume it via configuration.

What does it all mean?

Now that plugins are easy to build, release, and consume, we will move toward much smaller logically separated code bases. Over time we'll extract commands from yetibot and yetibot/core in to separate plugins. This will make features easier to work with, test in isolation, and release.

Here's the PR that enabled plugins. The change itself was quite small.

Check out the new Dynamic plugins docs, and as always please give us feedback by leaving a comment below, chatting with us in Slack, or opening a GitHub issue.

core 2020