]> git.immae.eu Git - perso/Immae/Config/Nix.git/blobdiff - flakes/private/buildbot/common/build_helpers.py
Squash changes containing private information
[perso/Immae/Config/Nix.git] / flakes / private / buildbot / common / build_helpers.py
similarity index 62%
rename from modules/private/buildbot/common/build_helpers.py
rename to flakes/private/buildbot/common/build_helpers.py
index acea90591f5ca16b524e0e41b7d22087ef72cf7c..77e6c074c5c4bc71777a218dab48b0c9e580df04 100644 (file)
@@ -3,9 +3,12 @@ from buildbot_buildslist import BuildsList
 from shutil import which
 
 __all__ = [
-        "force_scheduler", "deploy_scheduler", "hook_scheduler",
-        "clean_branch", "package_and_upload", "SlackStatusPush",
-        "XMPPStatusPush", "NixShellCommand"
+        "force_scheduler", "deploy_scheduler", "git_hook_scheduler",
+        "clean_branch", "package_and_upload", "AppriseStatusPush",
+        "XMPPStatusPush", "NixShellCommand",
+        "all_builder_names", "compute_build_infos", "deploy_ssh_command",
+        "configure_apprise_push",
+        "configure_xmpp_push", "deploy_hook_scheduler",
         ]
 
 # Small helpers"
@@ -19,22 +22,21 @@ def clean_branch(props):
 def package_and_upload(package, package_dest, package_url):
     return [
             steps.ShellCommand(name="build package",
-                logEnviron=False, haltOnFailure=True, workdir="source",
+                logEnviron=False, haltOnFailure=True,
                 command=["git", "archive", "HEAD", "-o", package]),
 
             steps.FileUpload(name="upload package", workersrc=package,
-                workdir="source", masterdest=package_dest,
+                masterdest=package_dest,
                 url=package_url, mode=0o644),
 
             steps.ShellCommand(name="cleanup package", logEnviron=False,
-                haltOnFailure=True, workdir="source", alwaysRun=True,
+                haltOnFailure=True, alwaysRun=True,
                 command=["rm", "-f", package]),
             ]
 
 # Steps
 class NixShellCommand(steps.ShellCommand):
-    def __init__(self, command=None, pure=True, nixfile=None, **kwargs):
-        assert(isinstance(command, str))
+    def __init__(self, command=None, nixPackages=[], pure=True, nixFile=None, nixIncludes={}, nixArgs={}, **kwargs):
         oldpath = kwargs.get("env", {}).get("PATH", None)
         if which("nix-shell", path=oldpath) is None:
             kwargs["env"] = kwargs.get("env", {})
@@ -43,23 +45,37 @@ class NixShellCommand(steps.ShellCommand):
             elif isinstance(oldpath, list):
                 kwargs["env"]["PATH"] = ["/run/current-system/sw/bin"] + oldpath
         nixcommand = ["nix-shell"]
+        for k, v in nixArgs.items():
+            nixcommand.append("--arg")
+            nixcommand.append(k)
+            nixcommand.append(v)
         if pure:
             nixcommand.append("--pure")
+        for k, v in nixIncludes.items():
+            nixcommand.append("-I")
+            nixcommand.append("{}={}".format(k, v))
         nixcommand.append("--run")
         nixcommand.append(command)
-        if nixfile is not None:
-            nixcommand.append(nixfile)
+        if len(nixPackages) > 0:
+            nixcommand.append("-p")
+            nixcommand += nixPackages
+        elif nixFile is not None:
+            nixcommand.append(nixFile)
         super().__init__(command=nixcommand, **kwargs)
 
 # Schedulers
-def force_scheduler(name, builders):
+def force_scheduler(name, builders, nobranch=False):
+    if nobranch:
+        branch = util.FixedParameter(name="branch", default="")
+    else:
+        branch=util.StringParameter(name="branch", label="Git reference (tag, branch)", required=True)
+
     return schedulers.ForceScheduler(name=name,
         label="Force build", buttonName="Force build",
         reason=util.StringParameter(name="reason", label="Reason", default="Force build"),
         codebases=[
             util.CodebaseParameter("",
-                branch=util.StringParameter(
-                    name="branch", label="Git reference (tag, branch)", required=True),
+                branch=branch,
                 revision=util.FixedParameter(name="revision", default=""),
                 repository=util.FixedParameter(name="repository", default=""),
                 project=util.FixedParameter(name="project", default=""),
@@ -88,50 +104,51 @@ def deploy_scheduler(name, builders):
             ]
         )
 
-def hook_scheduler(project, timer=10):
+def git_hook_scheduler(project, builders=[], timer=1):
+    if len(builders) == 0:
+        builders = ["{}_build".format(project)]
+    return schedulers.AnyBranchScheduler(
+            change_filter=util.ChangeFilter(category="gitolite-hooks", project=project),
+            name="{}_git_hook".format(project), treeStableTimer=timer, builderNames=builders)
+
+def deploy_hook_scheduler(project, builders, timer=1):
     return schedulers.AnyBranchScheduler(
-            change_filter=util.ChangeFilter(category="hooks", project=project),
-            name=project, treeStableTimer=timer, builderNames=["{}_build".format(project)])
+            change_filter=util.ChangeFilter(category="deploy_webhook", project=project),
+            name="{}_deploy".format(project), treeStableTimer=timer, builderNames=builders)
 
-# Slack/XMPP status push
+# Builders
+def all_builder_names(c):
+    return [builder.name for builder in c['builders']]
+
+# Apprise/XMPP status push
 from buildbot.reporters.http import HttpStatusPushBase
 from twisted.internet import defer
 from twisted.python import log
-from buildbot.util import httpclientservice
 from buildbot.reporters import utils
 from buildbot.process import results
 from twisted.words.protocols.jabber.jid import JID
 from wokkel import client, xmppim
 from functools import partial
+import apprise
 
-class SlackStatusPush(HttpStatusPushBase):
-    name = "SlackStatusPush"
+class AppriseStatusPush(HttpStatusPushBase):
+    name = "AppriseStatusPush"
 
     @defer.inlineCallbacks
-    def reconfigService(self, serverUrl, **kwargs):
+    def reconfigService(self, appriseUrls, **kwargs):
+        self.appriseUrls = appriseUrls
         yield HttpStatusPushBase.reconfigService(self, **kwargs)
-        self._http = yield httpclientservice.HTTPClientService.getService(
-            self.master, serverUrl)
 
     @defer.inlineCallbacks
     def send(self, build):
         yield utils.getDetailsForBuild(self.master, build, wantProperties=True)
-        response = yield self._http.post("", json=self.format(build))
-        if response.code != 200:
-            log.msg("%s: unable to upload status: %s" %
-                    (response.code, response.content))
+        appobject = apprise.Apprise()
+        message = self.format(build)
+        for url in self.appriseUrls:
+            appobject.add(url.format(**message))
+        yield appobject.notify(title=message["title"], body=message["text"])
 
     def format(self, build):
-        colors = [
-                "#36A64F", # success
-                "#F1E903", # warnings
-                "#DA0505", # failure
-                "#FFFFFF", # skipped
-                "#000000", # exception
-                "#FFFFFF", # retry
-                "#D02CA9", # cancelled
-                ]
-
         if "environment" in build["properties"]:
             msg = "{} environment".format(build["properties"]["environment"][0])
             if "build" in build["properties"]:
@@ -152,67 +169,31 @@ class SlackStatusPush(HttpStatusPushBase):
             else:
                 duration = "{}s".format(seconds)
 
-            text = "Build <{}|{}> of {}'s {} was {} in {}.".format(
-                    build["url"], build["buildid"],
+            text = "Build {} ({}) of {}'s {} was {} in {}.".format(
+                    build["number"], build["url"],
                     build["builder"]["name"],
                     msg,
                     results.Results[build["results"]],
                     duration,
                     )
-            fields = [
-                    {
-                        "title": "Build",
-                        "value": "<{}|{}>".format(build["url"], build["buildid"]),
-                        "short": True,
-                        },
-                    {
-                        "title": "Project",
-                        "value": build["builder"]["name"],
-                        "short": True,
-                        },
-                    {
-                        "title": "Build status",
-                        "value": results.Results[build["results"]],
-                        "short": True,
-                        },
-                    {
-                        "title": "Build duration",
-                        "value": duration,
-                        "short": True,
-                        },
-                    ]
-            if "environment" in build["properties"]:
-                fields.append({
-                        "title": "Environment",
-                        "value": build["properties"]["environment"][0],
-                        "short": True,
-                    })
-            if "build" in build["properties"]:
-                fields.append({
-                        "title": "Archive",
-                        "value": build["properties"]["build"][0],
-                        "short": True,
-                    })
-            attachments = [{
-                    "fallback": "",
-                    "color": colors[build["results"]],
-                    "fields": fields
-                    }]
         else:
-            text = "Build <{}|{}> of {}'s {} started.".format(
-                    build["url"], build["buildid"],
+            text = "Build {} ({}) of {}'s {} started.".format(
+                    build["number"], build["url"],
                     build["builder"]["name"],
                     msg,
                     )
-            attachments = []
-
         return {
                 "username": "Buildbot",
-                "icon_url": "http://docs.buildbot.net/current/_static/icon.png",
+                "image_url": "http://docs.buildbot.net/current/_static/icon.png",
                 "text": text,
-                "attachments": attachments,
+                "title": "",
                 }
 
+def configure_apprise_push(c, secrets_file, builders):
+    c['services'].append(AppriseStatusPush(
+        name="apprise_status", builders=builders,
+        appriseUrls=open(secrets_file + "/apprise_webhooks", "r").read().split("\n")))
+
 class XMPPStatusPush(HttpStatusPushBase):
     name = "XMPPStatusPush"
 
@@ -261,7 +242,7 @@ class XMPPStatusPush(HttpStatusPushBase):
                 duration = "{}s".format(seconds)
 
             text = "Build {} ( {} ) of {}'s {} was {} in {}.".format(
-                    build["buildid"], build["url"],
+                    build["number"], build["url"],
                     build["builder"]["name"],
                     msg,
                     results.Results[build["results"]],
@@ -269,9 +250,44 @@ class XMPPStatusPush(HttpStatusPushBase):
                     )
         else:
             text = "Build {} ( {} ) of {}'s {} started.".format(
-                    build["buildid"], build["url"],
+                    build["number"], build["url"],
                     build["builder"]["name"],
                     msg,
                     )
 
         return text
+
+def configure_xmpp_push(c, secrets_file, builders, recipients):
+    c['services'].append(XMPPStatusPush(
+        name="xmpp_status", builders=builders, recipients=recipients,
+        password=open(secrets_file + "/notify_xmpp_password", "r").read().rstrip()))
+
+# LDAP edit
+from buildbot.process.buildstep import FAILURE
+from buildbot.process.buildstep import SUCCESS
+from buildbot.process.buildstep import BuildStep
+
+def compute_build_infos(prefix, release_path):
+    @util.renderer
+    def compute(props):
+        import re, hashlib
+        build_file = props.getProperty("build")
+        package_dest = "{}/{}".format(release_path, build_file)
+        version = re.match(r"{0}_(.*).tar.gz".format(prefix), build_file).group(1)
+        with open(package_dest, "rb") as f:
+            sha = hashlib.sha256(f.read()).hexdigest()
+        return {
+                "build_version": version,
+                "build_hash": sha,
+                }
+    return compute
+
+def deploy_ssh_command(ssh_key_path, deploy_hosts):
+    @util.renderer
+    def compute(props):
+        environment = props["environment"] if props.hasProperty("environment") else "integration"
+        ssh_command = [
+                "ssh", "-o", "UserKnownHostsFile=/dev/null", "-o", "StrictHostKeyChecking=no", "-o", "CheckHostIP=no",
+                "-i", ssh_key_path ]
+        return ssh_command + deploy_hosts.get(environment, ["host.invalid"])
+    return compute