GitLab Listener
An autonomous daemon process for web servers, connecting with GitLab webhooks, allowing custom actions to be bound to configurable events. Accepts and parses GitLab events, allows filtering by various properties and can execute any command or script as a reaction. Built with Perfect, written in Swift.
Public Presence: gitlab.com/apricum/gitlab-listener
Downloads: gitlab.com/apricum/gitlab-listener/-/releases
Introduction
The world of the automated internet is an intricate one; a world filled with many processes, wanton memory use, monolithic and microscopic systems alike, applications in isolation and communication, chaotic shell scripts and orderly instruction files, an environment telling countless tales of high efforts and low yields, of overcomplication and underperforming, unwavering stability and constant and untraceable failures, a set-up running on a Mac Mini half concealed under the desk or cross-country distributed data centres.
My personal upshot from this introduction is: Automation should be applied whenever possible. Once any process is sufficiently digital, it should be possible to automate it. Even though many frameworks for automating repetitive, manual tasks are widely adopted in web development at the time of writing, finding solutions to issues at a smaller scale can be a challenge. I found that, more often than not, popular choices are intricate, require more than a bit of preparation, much reading of documentation with an all too commonly found lack of examples and references, then followed by configuration and testing. Different approaches later demand frequent maintenance or recurring payment in the case of subscription services. The popular choice might often be an advanced choice, too, and sometimes, a simpler approach fits best.
GitLab Listener is a pragmatic approach to a straightforward task: coupling an action to a GitLab event. It listens for events sent as GitLab’s webhooks and, if it receives one, can execute an action, for instance, a command, a script, or another process.
Motivation
My motivation for Listener arose from trying to find a small-scale solution for autonomous and self-contained deployment. It allows even tiny, single cloud instances to have a fully automated release set-up without the need for external services like a build or testing server. Even less complex contraptions on the web or simple, static sites (like a personal homepage, an online portfolio, or a small game) benefit from automatic releases. Without an automation set-up, manual interaction is always required for any new release to be prepared and published.
For a common, bare bones server, for example, I'd have to log into a cloud instance, shut the services of the old version down, navigate around, pull in new changes, and restart whatever services need to be restarted. On the other end of the complexity spectrum, I'd have an interconnected web of external services that pre-package my application, run tests for me, and send it to its final destination — while useful, this is almost always overboard for smaller projects. If my server could do all of that on its own and know when to do so, that would be immensely helpful.
The following is an example put together from a use case very similar to how I'm frequently using GitLab Listener in private servers for various smaller-scale web projects where more complex workflows are not needed.
We picture a custom web app, that has just built; it has just been deployed on a remote server for the first time. Of course, the app's code is version controlled with Git and could be pulled in easily from a repository. Once new changes are merged into the remote master
branch, the server should now pull in these changes on its own and restart the relevant services. We can use Listener in this scenario to await a push to master
on GitLab and trigger the update and reload as a consequence.
Translating this example into the way Listener is configured, we would specify a command with the kind push
and restrict it to only react if the changes are made to the ref refs/heads/master
. The command we configure can be any shell executable: a chain of commands, a script file, or a completely separate application.
Listener reacts to GitLab events dispatched via webhooks, but it can also act on simple custom events in the form of HTTP requests, essentially offering a custom webhook of its own, that can be called at any time from the outside, just by knowing the secret route. By extension, these user instructions can also be used as arbitrary endpoints for other services or applications to call. The route for all user instructions has the format /user/<tag>
, consisting of the base /user
and a custom-definable user tag. This tag can be created in Listener's configuration and is set to identify and distinguish available actions.
As for an example with a third-party service hooking into Listener, we might have a CMS or a database holding the data presented by the application. An editor saves changes somewhere in an environment they're already aquainted with, they save and upload their changes to a remote repository; A user instruction may then be set up for an endpoint /user/update-database
with an action to fetch and publish the new state of the CMS or database. Alternatively, a secret URL could be passed along to content editors, to open at any time in their browser to trigger an update on demand.
Conclusion
This write-up aims to give an initial impression of what GitLab Listener does and what it may be used for. Additional information, usage examples and documentation on topics like installing it on server instances and providing configuration for individual commands can be found with the mark-up included in Listener’s repository at gitlab.com/apricum/gitlab-listener.