Prosodical Thoughts

News, announcements and thoughts from the Prosody IM team

Pubsub Commit Notifications

by The Prosody Team
Tags: pubsub

If you have been in our MUC you may have noticed our commit notifications and other announcements. This blog post explains how this is setup.


  1. A commit (or many) is pushed a public repository.
  2. A hook in the repository formats the commit log as an Atom feed.
  3. This is sent with cURL to mod_pubsub_post.
  4. Each item in the feed is published as a PubSub item.
  5. A chatbot subscribed to these receives and posts them in a MUC.

Prosody configuration

On the Prosody side, mod_pubsub_post is used to handle incoming webhooks and publish the data to pubsub.

Configuration looks like this:

Component "" "pubsub"
modules_enabled = {
http_host = "localhost"
pubsub_post_actor = "request.ip"

PubSub nodes can be created and configured from a client but finding one that supports this is a challenge. Instead we have a module that creates and configures all the nodes we need. This also helps with keeping track of what nodes there are and to recreate them in case of data loss.

The module looks something like this:

-- mod_pubsub_prosodyim
local mod_pubsub = module:depends("pubsub");
local pubsub = mod_pubsub.service;

pubsub:create("commits", true);
pubsub:set_node_config("commits", true, {
        title = "Commit feed";
        description = "Feed of commits pushed to the project";
        payload_type = "",
pubsub:set_affiliation("commits", true, "", "publisher");
pubsub:add_subscription("commits", true, "");

This also grants publish permission to which is the actor mod_pubsub_post will act as when receiving data from Mercurial.

Mercurial configuration

We use Mercurial, so this section explains how to configure that.

If you use a different VCS then you get the privilege of figuring this part out yourself.

Atom Template

mod_pubsub_post supports sending multiple items in the form of an Atom feed, so here we will teach Mercurial how to format a commit log like an Atom feed.

We added this in /etc/mercurial/hgrc.d/atom.rc to define an atom template:

atom = "<entry>{atom_id}{atom_title}{atom_author}{atom_published}{atom_summary}</entry>\n"
atom:docheader = "<feed xmlns=''>\n"
atom:docfooter = "</feed>\n"

atom_id = "<id>,{date|shortdate}:{node}</id>"
atom_title = "<title>{desc|firstline|escape}</title>"
atom_author = "<author><name>{author|person|escape}</name><email>{author|email|escape}</email></author>"
atom_published = "<published>{date|rfc3339date|escape}</published>"
atom_summary = "<summary>{author|person|escape} committed: {desc|firstline|escape}</summary>"

You most likely want to change the domain name in atom_id to match your own.

The template is broken up into parts for each Atom element to make it easy to customize which to include.


In the repository, in the file .hg/hgrc we have (among a few other settings):

changegroup.pubsub_post = $HG log -r $HG_NODE:$HG_NODE_LAST -T atom |
    curl -sSf http://localhost:5280/pubsub_post/commits -H "Content-Type: application/atom+xml" --data-binary @-

The last part in the URL (here commits) is the PubSub node that we publish to.

Chat bot and the actual notifications

To actually get the PubSub notifications into a MUC, we use a Riddim based bot and the pubsub2room plugin, which subscribes to a PubSub node and relays notifications with some formatting applied.

The bot is configured something like this:

pubsub2room = {
    [""] = {
        room = "";
        template = "${} committed: ${title}";

Thus you get

Dave committed: mod_ping: Send pongs


Prosody is a lightweight and flexible XMPP server designed with ease-of-use and extensibility in mind.

⚛️ Atom feed

Recent Posts