← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~twom/lpbuildbot/mattermost-notifier into lp:lpbuildbot

 

Tom Wardill has proposed merging lp:~twom/lpbuildbot/mattermost-notifier into lp:lpbuildbot.

Commit message:
Add mattermost notifier

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~twom/lpbuildbot/mattermost-notifier/+merge/397038

Add notifier code for sending a mattermost webhook. The webhook url is considered a secret, so defend against it not being defined in this branch master.cfg.

Also name the build steps so they produce prettier output.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~twom/lpbuildbot/mattermost-notifier into lp:lpbuildbot.
=== added file 'lpbuildbot/mattermost.py'
--- lpbuildbot/mattermost.py	1970-01-01 00:00:00 +0000
+++ lpbuildbot/mattermost.py	2021-01-27 17:36:58 +0000
@@ -0,0 +1,110 @@
+import json
+
+import requests
+from twisted.python import log as twlog
+
+from buildbot.status.base import StatusReceiverMultiService
+from buildbot.status.results import Results
+
+
+class MattermostNotifier(StatusReceiverMultiService):
+
+    def __init__(self, webhook_url, channel, author):
+        StatusReceiverMultiService.__init__(self)
+        self.webhook_url = webhook_url
+        self.channel = channel
+        self.author = author
+
+    def _transmit(self, payload):
+        payload["channel"] = self.channel
+        payload["author_name"] = self.author
+
+        requests.post(
+            self.webhook_url,
+            data=json.dumps(payload),
+            headers={"Content-type": "application/json"}
+        )
+
+    def builderAdded(self, builderName, builder):
+        twlog.msg("Mattermost notifier: builder added")
+        builder.subscribe(self)
+
+    def buildStarted(self, builderName, build):
+        twlog.msg("Mattermost notifier: build started")
+        build.subscribe(self)
+
+        payload = {
+            "attachments": [{
+                "title": "Build started",
+                "title_link": self.status.getURLForThing(build),
+                "color": "#0000FF",
+                "text": "Build number {} of {} has started on {}".format(
+                    build.getNumber(), builderName, build.getSlavename()),
+                "fields": [
+                    {
+                        "short": True,
+                        "title": "Revision",
+                        "value": build.getSourceStamp().revision
+                    },
+                    {
+                        "short": True,
+                        "title": "Reason",
+                        "value": build.getReason()
+                    }]
+            }]
+        }
+
+        self._transmit(payload)
+
+    def buildFinished(self, builderName, build, results):
+
+        word = Results[results]
+        colors = ["#00FF00", "#00FFFF", "#FF0000",
+                  "#00FFFF", "#FFFF00", "#00FFFF"]
+        color = colors[results]
+
+        payload = {
+            "attachments": [{
+                "title": "Build {}: {}".format(build.getNumber(), word),
+                "title_link": self.status.getURLForThing(build),
+                "color": color,
+                "text": "Build number {} of {} has completed with {}.".format(
+                    build.getNumber(), builderName, word),
+                "fields": [{
+                    "short": False,
+                    "title": "Responsible users",
+                    "value": build.getResponsibleUsers()
+                },
+                {
+                    "short": True,
+                    "title": "Revision",
+                    "value": build.getSourceStamp().revision
+                },
+                {
+                    "short": True,
+                    "title": "Reason",
+                    "value": build.getReason()
+                }]
+            }]
+        }
+
+        for count, step in enumerate(build.getSteps()):
+            result, _ = step.getResults()
+            if result != 0:
+                payload['attachments'][0]['fields'].append({
+                    "short": True,
+                    "title": "Failed step: {}".format(count),
+                    "value": step.getName()
+                })
+                break
+
+        self._transmit(payload)
+
+
+    def setServiceParent(self, parent):
+        StatusReceiverMultiService.setServiceParent(self, parent)
+        self.status = parent.getStatus()
+
+        self.status.subscribe(self)
+
+        twlog.msg("Mattermost notifier configured")

=== modified file 'master.cfg'
--- master.cfg	2021-01-07 09:32:46 +0000
+++ master.cfg	2021-01-27 17:36:58 +0000
@@ -76,44 +76,52 @@
 
 def addEnvironmentPrepSteps(fac, tree, container, variables=None):
     fac.addStep(lpbuildbot.shell.ShellCommand(
+        name="link-external-sourcecode",
         command=['./utilities/link-external-sourcecode',
                  '-p', "{}/dependencies".format(tree)],
         description=['linking', 'dependencies'],
         descriptionDone=['link', 'dependencies'],
         workdir="{}/devel".format(tree)))
     fac.addStep(lpbuildbot.shell.ShellCommand(
+        name="update-sourcecode",
         command=['./utilities/update-sourcecode', '--use-http'],
         description=['pulling', 'new', 'sourcecode', 'revisions'],
         descriptionDone=['pull', 'new', 'sourcecode', 'revisions'],
         workdir="{}/devel".format(tree)))
     fac.addStep(lpbuildbot.shell.ShellCommand(
+        name="git pull download-cache",
         command=['git', 'pull'],
         description=['updating', 'download', 'cache'],
         descriptionDone=['update', 'download', 'cache'],
         workdir="{}/devel/download-cache".format(tree)))
     fac.addStep(transfer.FileDownload(
+        name="Download testr.conf",
         mastersrc='testr.conf',
         slavedest='.testr.conf',
         mode=0o644,
         workdir="{}/devel".format(tree)))
     # Clean up any potential cruft left around by lxd from a previous run.
     fac.addStep(lpbuildbot.shell.ShellCommand(
+        name="lp-setup-lxd-cleanup",
         command=['/usr/bin/lp-setup-lxd-cleanup', container],
         description=['cleanup','previous','lxd','containers'],
         descriptionDone=['cleaned','previous','lxd','containers'],
         workdir="{}/devel".format(tree)))
     fac.addStep(transfer.FileDownload(
+        name="Downlad init_testr.py",
         mastersrc='scripts/init_testr.py',
         slavedest='init_testr.py',
         mode=0o544,
         workdir="{}/devel".format(tree)))
     fac.addStep(lpbuildbot.shell.ShellCommand(
+        name="init_testr.py",
         command=['./init_testr.py'],
         description=['initializing', 'testrepository'],
         descriptionDone=['initialized', 'testrepository'],
         workdir="{}/devel".format(tree)))
     # Make a temp dir, to work around bug 808557.
     fac.addStep(lpbuildbot.shell.ShellCommand(
+        name="make temp dir",
         command=['mkdir', 'temp'],
         workdir="{}/devel".format(tree)))
     build_command = ['/usr/bin/lp-setup-lxd-build', container, tree]
@@ -121,6 +129,7 @@
         for key, value in variables.items():
             build_command.append("--variable={}={}".format(key, value))
     fac.addStep(lpbuildbot.shell.ShellCommand(
+        name="Build in base lxd",
         command=build_command,
         description=['building', 'in', 'base', 'lxd', 'container'],
         descriptionDone=['build', 'in', 'base', 'lxd', 'container'],
@@ -223,12 +232,16 @@
         lookup=lpbuildbot.mail.PassThroughLookup(),
         builders=['lp-devel-xenial', 'lp-db-devel-xenial']))
 
-# at the time of this writing, the buildbot IRC client does not support SSL
-# so we would need to modify buildbot to use this.  Supposedly Twisted's IRC
-# code does support SSL, so this might not be hard to change.
-# from buildbot.status import words
-# c['status'].append(words.IRC(host="irc.example.com", nick="bb",
-#                              channels=["#example"]))
+# Notify the mattermost channel
+# this is defined in the production config branch
+mattermost_hook_url = None
+if mattermost_hook_url:
+    import lpbuildbot.mattermost
+    c['status'].append(
+        lpbuildbot.mattermost.MattermostNotifier(
+            mattermost_hook_url,
+            "launchpad-alerts",
+            "lpbuildbot")) # this is ignored by chat.c.c config
 
 
 ####### DEBUGGING OPTIONS


Follow ups